summaryrefslogtreecommitdiffstats
path: root/src/dom/js
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/dom/js
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/dom/js')
-rw-r--r--src/dom/js/Makefile1471
-rw-r--r--src/dom/js/README20
-rw-r--r--src/dom/js/fdlibm/e_acos.c147
-rw-r--r--src/dom/js/fdlibm/e_acosh.c105
-rw-r--r--src/dom/js/fdlibm/e_asin.c156
-rw-r--r--src/dom/js/fdlibm/e_atan2.c165
-rw-r--r--src/dom/js/fdlibm/e_atanh.c110
-rw-r--r--src/dom/js/fdlibm/e_cosh.c133
-rw-r--r--src/dom/js/fdlibm/e_exp.c202
-rw-r--r--src/dom/js/fdlibm/e_fmod.c184
-rw-r--r--src/dom/js/fdlibm/e_gamma.c71
-rw-r--r--src/dom/js/fdlibm/e_gamma_r.c70
-rw-r--r--src/dom/js/fdlibm/e_hypot.c173
-rw-r--r--src/dom/js/fdlibm/e_j0.c524
-rw-r--r--src/dom/js/fdlibm/e_j1.c523
-rw-r--r--src/dom/js/fdlibm/e_jn.c315
-rw-r--r--src/dom/js/fdlibm/e_lgamma.c71
-rw-r--r--src/dom/js/fdlibm/e_lgamma_r.c347
-rw-r--r--src/dom/js/fdlibm/e_log.c184
-rw-r--r--src/dom/js/fdlibm/e_log10.c134
-rw-r--r--src/dom/js/fdlibm/e_pow.c386
-rw-r--r--src/dom/js/fdlibm/e_rem_pio2.c221
-rw-r--r--src/dom/js/fdlibm/e_remainder.c120
-rw-r--r--src/dom/js/fdlibm/e_scalb.c89
-rw-r--r--src/dom/js/fdlibm/e_sinh.c122
-rw-r--r--src/dom/js/fdlibm/e_sqrt.c497
-rw-r--r--src/dom/js/fdlibm/fdlibm.h273
-rw-r--r--src/dom/js/fdlibm/k_cos.c134
-rw-r--r--src/dom/js/fdlibm/k_rem_pio2.c354
-rw-r--r--src/dom/js/fdlibm/k_sin.c114
-rw-r--r--src/dom/js/fdlibm/k_standard.c785
-rw-r--r--src/dom/js/fdlibm/k_tan.c170
-rw-r--r--src/dom/js/fdlibm/s_asinh.c101
-rw-r--r--src/dom/js/fdlibm/s_atan.c175
-rw-r--r--src/dom/js/fdlibm/s_cbrt.c133
-rw-r--r--src/dom/js/fdlibm/s_ceil.c120
-rw-r--r--src/dom/js/fdlibm/s_copysign.c72
-rw-r--r--src/dom/js/fdlibm/s_cos.c118
-rw-r--r--src/dom/js/fdlibm/s_erf.c356
-rw-r--r--src/dom/js/fdlibm/s_expm1.c267
-rw-r--r--src/dom/js/fdlibm/s_fabs.c70
-rw-r--r--src/dom/js/fdlibm/s_finite.c71
-rw-r--r--src/dom/js/fdlibm/s_floor.c121
-rw-r--r--src/dom/js/fdlibm/s_frexp.c99
-rw-r--r--src/dom/js/fdlibm/s_ilogb.c85
-rw-r--r--src/dom/js/fdlibm/s_isnan.c74
-rw-r--r--src/dom/js/fdlibm/s_ldexp.c66
-rw-r--r--src/dom/js/fdlibm/s_lib_version.c73
-rw-r--r--src/dom/js/fdlibm/s_log1p.c211
-rw-r--r--src/dom/js/fdlibm/s_logb.c79
-rw-r--r--src/dom/js/fdlibm/s_matherr.c64
-rw-r--r--src/dom/js/fdlibm/s_modf.c132
-rw-r--r--src/dom/js/fdlibm/s_nextafter.c124
-rw-r--r--src/dom/js/fdlibm/s_rint.c131
-rw-r--r--src/dom/js/fdlibm/s_scalbn.c107
-rw-r--r--src/dom/js/fdlibm/s_signgam.c40
-rw-r--r--src/dom/js/fdlibm/s_significand.c68
-rw-r--r--src/dom/js/fdlibm/s_sin.c118
-rw-r--r--src/dom/js/fdlibm/s_tan.c112
-rw-r--r--src/dom/js/fdlibm/s_tanh.c122
-rw-r--r--src/dom/js/fdlibm/w_acos.c78
-rw-r--r--src/dom/js/fdlibm/w_acosh.c78
-rw-r--r--src/dom/js/fdlibm/w_asin.c80
-rw-r--r--src/dom/js/fdlibm/w_atan2.c79
-rw-r--r--src/dom/js/fdlibm/w_atanh.c81
-rw-r--r--src/dom/js/fdlibm/w_cosh.c77
-rw-r--r--src/dom/js/fdlibm/w_exp.c88
-rw-r--r--src/dom/js/fdlibm/w_fmod.c78
-rw-r--r--src/dom/js/fdlibm/w_gamma.c85
-rw-r--r--src/dom/js/fdlibm/w_gamma_r.c81
-rw-r--r--src/dom/js/fdlibm/w_hypot.c78
-rw-r--r--src/dom/js/fdlibm/w_j0.c105
-rw-r--r--src/dom/js/fdlibm/w_j1.c106
-rw-r--r--src/dom/js/fdlibm/w_jn.c128
-rw-r--r--src/dom/js/fdlibm/w_lgamma.c85
-rw-r--r--src/dom/js/fdlibm/w_lgamma_r.c81
-rw-r--r--src/dom/js/fdlibm/w_log.c78
-rw-r--r--src/dom/js/fdlibm/w_log10.c81
-rw-r--r--src/dom/js/fdlibm/w_pow.c99
-rw-r--r--src/dom/js/fdlibm/w_remainder.c77
-rw-r--r--src/dom/js/fdlibm/w_scalb.c95
-rw-r--r--src/dom/js/fdlibm/w_sinh.c77
-rw-r--r--src/dom/js/fdlibm/w_sqrt.c77
-rw-r--r--src/dom/js/js.c2333
-rw-r--r--src/dom/js/js.mak4025
-rw-r--r--src/dom/js/js.msg251
-rw-r--r--src/dom/js/jsapi.c4187
-rw-r--r--src/dom/js/jsapi.h1752
-rw-r--r--src/dom/js/jsarena.c565
-rw-r--r--src/dom/js/jsarena.h302
-rw-r--r--src/dom/js/jsarray.c1429
-rw-r--r--src/dom/js/jsarray.h77
-rw-r--r--src/dom/js/jsatom.c911
-rw-r--r--src/dom/js/jsatom.h409
-rw-r--r--src/dom/js/jsautocfg.h50
-rw-r--r--src/dom/js/jsbit.h113
-rw-r--r--src/dom/js/jsbool.c244
-rw-r--r--src/dom/js/jsbool.h62
-rw-r--r--src/dom/js/jsclist.h139
-rw-r--r--src/dom/js/jscntxt.c702
-rw-r--r--src/dom/js/jscntxt.h496
-rw-r--r--src/dom/js/jscompat.h57
-rw-r--r--src/dom/js/jsconfig.h489
-rw-r--r--src/dom/js/jscpucfg.c377
-rw-r--r--src/dom/js/jscpucfg.h200
-rw-r--r--src/dom/js/jsdate.c2234
-rw-r--r--src/dom/js/jsdate.h118
-rw-r--r--src/dom/js/jsdbgapi.c1240
-rw-r--r--src/dom/js/jsdbgapi.h345
-rw-r--r--src/dom/js/jsdhash.c763
-rw-r--r--src/dom/js/jsdhash.h573
-rw-r--r--src/dom/js/jsdtoa.c3155
-rw-r--r--src/dom/js/jsdtoa.h130
-rw-r--r--src/dom/js/jsemit.c4471
-rw-r--r--src/dom/js/jsemit.h547
-rw-r--r--src/dom/js/jsexn.c1081
-rw-r--r--src/dom/js/jsexn.h102
-rw-r--r--src/dom/js/jsfile.c2610
-rw-r--r--src/dom/js/jsfile.h50
-rw-r--r--src/dom/js/jsfun.c2059
-rw-r--r--src/dom/js/jsfun.h151
-rw-r--r--src/dom/js/jsgc.c1423
-rw-r--r--src/dom/js/jsgc.h230
-rw-r--r--src/dom/js/jshash.c479
-rw-r--r--src/dom/js/jshash.h152
-rw-r--r--src/dom/js/jsinterp.c4284
-rw-r--r--src/dom/js/jsinterp.h292
-rw-r--r--src/dom/js/jslibmath.h290
-rw-r--r--src/dom/js/jslock.c1241
-rw-r--r--src/dom/js/jslock.h289
-rw-r--r--src/dom/js/jslocko.asm59
-rw-r--r--src/dom/js/jslog2.c83
-rw-r--r--src/dom/js/jslong.c281
-rw-r--r--src/dom/js/jslong.h437
-rw-r--r--src/dom/js/jsmath.c477
-rw-r--r--src/dom/js/jsmath.h55
-rw-r--r--src/dom/js/jsnum.c1058
-rw-r--r--src/dom/js/jsnum.h280
-rw-r--r--src/dom/js/jsobj.c3900
-rw-r--r--src/dom/js/jsobj.h464
-rw-r--r--src/dom/js/jsopcode.c2660
-rw-r--r--src/dom/js/jsopcode.h273
-rw-r--r--src/dom/js/jsopcode.tbl333
-rw-r--r--src/dom/js/jsosdep.h127
-rw-r--r--src/dom/js/jsotypes.h211
-rw-r--r--src/dom/js/jsparse.c3547
-rw-r--r--src/dom/js/jsparse.h337
-rw-r--r--src/dom/js/jsprf.c1212
-rw-r--r--src/dom/js/jsprf.h148
-rw-r--r--src/dom/js/jsprvtd.h174
-rw-r--r--src/dom/js/jspubtd.h564
-rw-r--r--src/dom/js/jsregexp.c3773
-rw-r--r--src/dom/js/jsregexp.h168
-rw-r--r--src/dom/js/jsscan.c1315
-rw-r--r--src/dom/js/jsscan.h264
-rw-r--r--src/dom/js/jsscope.c1581
-rw-r--r--src/dom/js/jsscope.h386
-rw-r--r--src/dom/js/jsscript.c1287
-rw-r--r--src/dom/js/jsscript.h178
-rw-r--r--src/dom/js/jsshell.msg50
-rw-r--r--src/dom/js/jsstddef.h83
-rw-r--r--src/dom/js/jsstr.c4502
-rw-r--r--src/dom/js/jsstr.h439
-rw-r--r--src/dom/js/jstypes.h388
-rw-r--r--src/dom/js/jsutil.c157
-rw-r--r--src/dom/js/jsutil.h106
-rw-r--r--src/dom/js/jsxdrapi.c690
-rw-r--r--src/dom/js/jsxdrapi.h193
-rw-r--r--src/dom/js/prmjtime.c646
-rw-r--r--src/dom/js/prmjtime.h95
-rw-r--r--src/dom/js/resource.h15
171 files changed, 94126 insertions, 0 deletions
diff --git a/src/dom/js/Makefile b/src/dom/js/Makefile
new file mode 100644
index 000000000..bd7ee7360
--- /dev/null
+++ b/src/dom/js/Makefile
@@ -0,0 +1,1471 @@
+# #################################
+# Unix/Linux makefile for libjs.a
+# #################################
+
+
+CC=gcc
+CFLAGS= -O2 -DXP_UNIX
+
+all: js
+
+INC += -Ifdlibm
+
+OBJ = \
+ fdlibm/e_acos.o \
+ fdlibm/e_acosh.o \
+ fdlibm/e_asin.o \
+ fdlibm/e_atan2.o \
+ fdlibm/e_atanh.o \
+ fdlibm/e_cosh.o \
+ fdlibm/e_exp.o \
+ fdlibm/e_fmod.o \
+ fdlibm/e_gamma.o \
+ fdlibm/e_gamma_r.o \
+ fdlibm/e_hypot.o \
+ fdlibm/e_j0.o \
+ fdlibm/e_j1.o \
+ fdlibm/e_jn.o \
+ fdlibm/e_lgamma.o \
+ fdlibm/e_lgamma_r.o \
+ fdlibm/e_log.o \
+ fdlibm/e_log10.o \
+ fdlibm/e_pow.o \
+ fdlibm/e_rem_pio2.o \
+ fdlibm/e_remainder.o \
+ fdlibm/e_scalb.o \
+ fdlibm/e_sinh.o \
+ fdlibm/e_sqrt.o \
+ fdlibm/k_cos.o \
+ fdlibm/k_rem_pio2.o \
+ fdlibm/k_sin.o \
+ fdlibm/k_standard.o \
+ fdlibm/k_tan.o \
+ fdlibm/s_asinh.o \
+ fdlibm/s_atan.o \
+ fdlibm/s_cbrt.o \
+ fdlibm/s_ceil.o \
+ fdlibm/s_copysign.o \
+ fdlibm/s_cos.o \
+ fdlibm/s_erf.o \
+ fdlibm/s_expm1.o \
+ fdlibm/s_fabs.o \
+ fdlibm/s_finite.o \
+ fdlibm/s_floor.o \
+ fdlibm/s_frexp.o \
+ fdlibm/s_ilogb.o \
+ fdlibm/s_isnan.o \
+ fdlibm/s_ldexp.o \
+ fdlibm/s_lib_version.o \
+ fdlibm/s_log1p.o \
+ fdlibm/s_logb.o \
+ fdlibm/s_matherr.o \
+ fdlibm/s_modf.o \
+ fdlibm/s_nextafter.o \
+ fdlibm/s_rint.o \
+ fdlibm/s_scalbn.o \
+ fdlibm/s_signgam.o \
+ fdlibm/s_significand.o \
+ fdlibm/s_sin.o \
+ fdlibm/s_tan.o \
+ fdlibm/s_tanh.o \
+ fdlibm/w_acos.o \
+ fdlibm/w_acosh.o \
+ fdlibm/w_asin.o \
+ fdlibm/w_atan2.o \
+ fdlibm/w_atanh.o \
+ fdlibm/w_cosh.o \
+ fdlibm/w_exp.o \
+ fdlibm/w_fmod.o \
+ fdlibm/w_gamma.o \
+ fdlibm/w_gamma_r.o \
+ fdlibm/w_hypot.o \
+ fdlibm/w_j0.o \
+ fdlibm/w_j1.o \
+ fdlibm/w_jn.o \
+ fdlibm/w_lgamma.o \
+ fdlibm/w_lgamma_r.o \
+ fdlibm/w_log.o \
+ fdlibm/w_log10.o \
+ fdlibm/w_pow.o \
+ fdlibm/w_remainder.o \
+ fdlibm/w_scalb.o \
+ fdlibm/w_sinh.o \
+ fdlibm/w_sqrt.o \
+ jsapi.o \
+ jsarena.o \
+ jsarray.o \
+ jsatom.o \
+ jsbool.o \
+ jscntxt.o \
+ jscpucfg.o \
+ jsdate.o \
+ jsdbgapi.o \
+ jsdhash.o \
+ jsdtoa.o \
+ jsemit.o \
+ jsexn.o \
+ jsfile.o \
+ jsfun.o \
+ jsgc.o \
+ jshash.o \
+ jsinterp.o \
+ jslock.o \
+ jslog2.o \
+ jslong.o \
+ jsmath.o \
+ jsnum.o \
+ jsobj.o \
+ jsopcode.o \
+ jsparse.o \
+ jsprf.o \
+ jsregexp.o \
+ jsscan.o \
+ jsscope.o \
+ jsscript.o \
+ jsstr.o \
+ jsutil.o \
+ jsxdrapi.o \
+ prmjtime.o
+
+js: js.o libjs.a
+ $(CC) -o js js.o libjs.a -lm
+
+libjs.a: $(OBJ)
+ ar crv libjs.a $(OBJ)
+ ranlib libjs.a
+
+clean:
+ $(RM) js libjs.a $(OBJ)
+
+# ###########################
+# DEPENDENCIES
+# ###########################
+
+
+fdlibm/e_acos.o: \
+ fdlibm/e_acos.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_acosh.o: \
+ fdlibm/e_acosh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_asin.o: \
+ fdlibm/e_asin.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_atan2.o: \
+ fdlibm/e_atan2.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_atanh.o: \
+ fdlibm/e_atanh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_cosh.o: \
+ fdlibm/e_cosh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_exp.o: \
+ fdlibm/e_exp.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_fmod.o: \
+ fdlibm/e_fmod.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_gamma.o: \
+ fdlibm/e_gamma.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_gamma_r.o: \
+ fdlibm/e_gamma_r.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_hypot.o: \
+ fdlibm/e_hypot.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_j0.o: \
+ fdlibm/e_j0.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_j1.o: \
+ fdlibm/e_j1.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_jn.o: \
+ fdlibm/e_jn.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_lgamma.o: \
+ fdlibm/e_lgamma.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_lgamma_r.o: \
+ fdlibm/e_lgamma_r.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_log.o: \
+ fdlibm/e_log.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_log10.o: \
+ fdlibm/e_log10.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_pow.o: \
+ fdlibm/e_pow.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_rem_pio2.o: \
+ fdlibm/e_rem_pio2.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_remainder.o: \
+ fdlibm/e_remainder.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_scalb.o: \
+ fdlibm/e_scalb.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_sinh.o: \
+ fdlibm/e_sinh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/e_sqrt.o: \
+ fdlibm/e_sqrt.c \
+ fdlibm/fdlibm.h
+
+fdlibm/k_cos.o: \
+ fdlibm/k_cos.c \
+ fdlibm/fdlibm.h
+
+fdlibm/k_rem_pio2.o: \
+ fdlibm/k_rem_pio2.c \
+ fdlibm/fdlibm.h
+
+fdlibm/k_sin.o: \
+ fdlibm/k_sin.c \
+ fdlibm/fdlibm.h
+
+fdlibm/k_standard.o: \
+ fdlibm/k_standard.c \
+ fdlibm/fdlibm.h
+
+fdlibm/k_tan.o: \
+ fdlibm/k_tan.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_asinh.o: \
+ fdlibm/s_asinh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_atan.o: \
+ fdlibm/s_atan.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_cbrt.o: \
+ fdlibm/s_cbrt.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_ceil.o: \
+ fdlibm/s_ceil.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_copysign.o: \
+ fdlibm/s_copysign.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_cos.o: \
+ fdlibm/s_cos.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_erf.o: \
+ fdlibm/s_erf.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_expm1.o: \
+ fdlibm/s_expm1.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_fabs.o: \
+ fdlibm/s_fabs.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_finite.o: \
+ fdlibm/s_finite.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_floor.o: \
+ fdlibm/s_floor.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_frexp.o: \
+ fdlibm/s_frexp.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_ilogb.o: \
+ fdlibm/s_ilogb.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_isnan.o: \
+ fdlibm/s_isnan.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_ldexp.o: \
+ fdlibm/s_ldexp.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_lib_version.o: \
+ fdlibm/s_lib_version.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_log1p.o: \
+ fdlibm/s_log1p.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_logb.o: \
+ fdlibm/s_logb.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_matherr.o: \
+ fdlibm/s_matherr.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_modf.o: \
+ fdlibm/s_modf.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_nextafter.o: \
+ fdlibm/s_nextafter.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_rint.o: \
+ fdlibm/s_rint.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_scalbn.o: \
+ fdlibm/s_scalbn.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_signgam.o: \
+ fdlibm/s_signgam.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_significand.o: \
+ fdlibm/s_significand.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_sin.o: \
+ fdlibm/s_sin.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_tan.o: \
+ fdlibm/s_tan.c \
+ fdlibm/fdlibm.h
+
+fdlibm/s_tanh.o: \
+ fdlibm/s_tanh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_acos.o: \
+ fdlibm/w_acos.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_acosh.o: \
+ fdlibm/w_acosh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_asin.o: \
+ fdlibm/w_asin.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_atan2.o: \
+ fdlibm/w_atan2.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_atanh.o: \
+ fdlibm/w_atanh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_cosh.o: \
+ fdlibm/w_cosh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_exp.o: \
+ fdlibm/w_exp.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_fmod.o: \
+ fdlibm/w_fmod.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_gamma.o: \
+ fdlibm/w_gamma.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_gamma_r.o: \
+ fdlibm/w_gamma_r.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_hypot.o: \
+ fdlibm/w_hypot.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_j0.o: \
+ fdlibm/w_j0.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_j1.o: \
+ fdlibm/w_j1.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_jn.o: \
+ fdlibm/w_jn.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_lgamma.o: \
+ fdlibm/w_lgamma.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_lgamma_r.o: \
+ fdlibm/w_lgamma_r.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_log.o: \
+ fdlibm/w_log.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_log10.o: \
+ fdlibm/w_log10.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_pow.o: \
+ fdlibm/w_pow.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_remainder.o: \
+ fdlibm/w_remainder.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_scalb.o: \
+ fdlibm/w_scalb.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_sinh.o: \
+ fdlibm/w_sinh.c \
+ fdlibm/fdlibm.h
+
+fdlibm/w_sqrt.o: \
+ fdlibm/w_sqrt.c \
+ fdlibm/fdlibm.h
+
+js.o: \
+ js.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsemit.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsparse.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsapi.o: \
+ jsapi.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsbool.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdate.h \
+ jsdhash.h \
+ jsdtoa.h \
+ jsemit.h \
+ jsexn.h \
+ jsfile.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsmath.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsparse.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h \
+ prmjtime.h
+
+jsarena.o: \
+ jsarena.c \
+ jsarena.h \
+ jsbit.h \
+ jscompat.h \
+ jscpucfg.h \
+ jshash.h \
+ jslock.h \
+ jslong.h \
+ jsobj.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsscope.h \
+ jsstddef.h \
+ jstypes.h \
+ jsutil.h
+
+jsarray.o: \
+ jsarray.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsatom.o: \
+ jsatom.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsbool.o: \
+ jsbool.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsbool.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jscntxt.o: \
+ jscntxt.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsexn.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jscpucfg.o: \
+ jscpucfg.c
+
+jsdate.o: \
+ jsdate.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdate.h \
+ jsdhash.h \
+ jsdtoa.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h \
+ prmjtime.h
+
+jsdbgapi.o: \
+ jsdbgapi.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsemit.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsdhash.o: \
+ jsdhash.c \
+ jsbit.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsosdep.h \
+ jsotypes.h \
+ jstypes.h \
+ jsutil.h
+
+jsdtoa.o: \
+ jsdtoa.c \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdtoa.h \
+ jslibmath.h \
+ jslong.h \
+ jsnum.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jspubtd.h \
+ jsstddef.h \
+ jstypes.h \
+ jsutil.h
+
+jsemit.o: \
+ jsemit.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsbit.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsemit.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsparse.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsexn.o: \
+ jsexn.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsbit.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsexn.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsfile.o: \
+ jsfile.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdate.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsemit.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsparse.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsfun.o: \
+ jsfun.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsbit.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsexn.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsparse.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h \
+ jsxdrapi.h
+
+jsgc.o: \
+ jsgc.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jshash.o: \
+ jshash.c \
+ jsbit.h \
+ jscompat.h \
+ jscpucfg.h \
+ jshash.h \
+ jslong.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsstddef.h \
+ jstypes.h \
+ jsutil.h
+
+jsinterp.o: \
+ jsinterp.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsbool.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jslock.o: \
+ jslock.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsbit.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsdtoa.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsobj.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jslog2.o: \
+ jslog2.c \
+ jsbit.h \
+ jscpucfg.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsstddef.h \
+ jstypes.h
+
+jslong.o: \
+ jslong.c \
+ jscpucfg.h \
+ jslong.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsstddef.h \
+ jstypes.h
+
+jsmath.o: \
+ jsmath.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslibmath.h \
+ jslock.h \
+ jslong.h \
+ jsmath.h \
+ jsnum.h \
+ jsobj.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ prmjtime.h
+
+jsnum.o: \
+ jsnum.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsdtoa.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsobj.o: \
+ jsobj.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsbool.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h \
+ jsxdrapi.h
+
+jsopcode.o: \
+ jsopcode.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsdtoa.h \
+ jsemit.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsparse.o: \
+ jsparse.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsemit.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsparse.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsprf.o: \
+ jsprf.c \
+ jscpucfg.h \
+ jslong.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsstddef.h \
+ jstypes.h \
+ jsutil.h
+
+jsregexp.o: \
+ jsregexp.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h \
+ jsxdrapi.h
+
+jsscan.o: \
+ jsscan.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsdtoa.h \
+ jsemit.h \
+ jsexn.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscan.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsscope.o: \
+ jsscope.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsbit.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsscript.o: \
+ jsscript.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdbgapi.h \
+ jsdhash.h \
+ jsemit.h \
+ jsfun.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h \
+ jsxdrapi.h
+
+jsstr.o: \
+ jsstr.c \
+ jsapi.h \
+ jsarena.h \
+ jsarray.h \
+ jsatom.h \
+ jsbool.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsnum.h \
+ jsobj.h \
+ jsopcode.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h
+
+jsutil.o: \
+ jsutil.c \
+ jscpucfg.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsstddef.h \
+ jstypes.h \
+ jsutil.h
+
+jsxdrapi.o: \
+ jsxdrapi.c \
+ jsapi.h \
+ jsarena.h \
+ jsatom.h \
+ jsclist.h \
+ jscntxt.h \
+ jscompat.h \
+ jsconfig.h \
+ jscpucfg.h \
+ jsdhash.h \
+ jsgc.h \
+ jshash.h \
+ jsinterp.h \
+ jslock.h \
+ jslong.h \
+ jsobj.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsprvtd.h \
+ jspubtd.h \
+ jsregexp.h \
+ jsscope.h \
+ jsscript.h \
+ jsstddef.h \
+ jsstr.h \
+ jstypes.h \
+ jsutil.h \
+ jsxdrapi.h
+
+prmjtime.o: \
+ prmjtime.c \
+ jscompat.h \
+ jscpucfg.h \
+ jslong.h \
+ jsosdep.h \
+ jsotypes.h \
+ jsprf.h \
+ jsstddef.h \
+ jstypes.h \
+ jsutil.h \
+ prmjtime.h
+
diff --git a/src/dom/js/README b/src/dom/js/README
new file mode 100644
index 000000000..cca453245
--- /dev/null
+++ b/src/dom/js/README
@@ -0,0 +1,20 @@
+//#########################################################################
+//# $Id$
+//#########################################################################
+See:
+
+$PROJECT/src/ecma/README
+
+for more information.
+
+The source is unchanged from Mozilla.org's distribution with
+the minor difference:
+
+Line 142 in jstypes.h:
+#if defined(_WIN32) && !defined(__MWERKS__)
+is modified to
+#if defined(_WIN32) && !defined(__MWERKS__) && !defined(__GNUC__)
+to allow for static linking in Mingw on Win32.
+
+
+
diff --git a/src/dom/js/fdlibm/e_acos.c b/src/dom/js/fdlibm/e_acos.c
new file mode 100644
index 000000000..a07c1eebc
--- /dev/null
+++ b/src/dom/js/fdlibm/e_acos.c
@@ -0,0 +1,147 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_acos(x)
+ * Method :
+ * acos(x) = pi/2 - asin(x)
+ * acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c)
+ * For x>0.5
+ * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ * = 2asin(sqrt((1-x)/2))
+ * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z)
+ * = 2f + (2c + 2s*z*R(z))
+ * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ * for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ * acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+#ifdef __STDC__
+ double __ieee754_acos(double x)
+#else
+ double __ieee754_acos(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double df;
+ double z,p,q,r,w,s,c;
+ int hx,ix;
+ u.d = x;
+ hx = __HI(u);
+ ix = hx&0x7fffffff;
+ if(ix>=0x3ff00000) { /* |x| >= 1 */
+ if(((ix-0x3ff00000)|__LO(u))==0) { /* |x|==1 */
+ if(hx>0) return 0.0; /* acos(1) = 0 */
+ else return pi+2.0*pio2_lo; /* acos(-1)= pi */
+ }
+ return (x-x)/(x-x); /* acos(|x|>1) is NaN */
+ }
+ if(ix<0x3fe00000) { /* |x| < 0.5 */
+ if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ z = x*x;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ return pio2_hi - (x - (pio2_lo-x*r));
+ } else if (hx<0) { /* x < -0.5 */
+ z = (one+x)*0.5;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ s = fd_sqrt(z);
+ r = p/q;
+ w = r*s-pio2_lo;
+ return pi - 2.0*(s+w);
+ } else { /* x > 0.5 */
+ z = (one-x)*0.5;
+ s = fd_sqrt(z);
+ u.d = s;
+ __LO(u) = 0;
+ df = u.d;
+ c = (z-df*df)/(s+df);
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ w = r*s+c;
+ return 2.0*(df+w);
+ }
+}
diff --git a/src/dom/js/fdlibm/e_acosh.c b/src/dom/js/fdlibm/e_acosh.c
new file mode 100644
index 000000000..725cceefb
--- /dev/null
+++ b/src/dom/js/fdlibm/e_acosh.c
@@ -0,0 +1,105 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_acosh(x)
+ * Method :
+ * Based on
+ * acosh(x) = log [ x + sqrt(x*x-1) ]
+ * we have
+ * acosh(x) := log(x)+ln2, if x is large; else
+ * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ * acosh(x) is NaN with signal if x<1.
+ * acosh(NaN) is NaN without signal.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */
+
+#ifdef __STDC__
+ double __ieee754_acosh(double x)
+#else
+ double __ieee754_acosh(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double t;
+ int hx;
+ u.d = x;
+ hx = __HI(u);
+ if(hx<0x3ff00000) { /* x < 1 */
+ return (x-x)/(x-x);
+ } else if(hx >=0x41b00000) { /* x > 2**28 */
+ if(hx >=0x7ff00000) { /* x is inf of NaN */
+ return x+x;
+ } else
+ return __ieee754_log(x)+ln2; /* acosh(huge)=log(2x) */
+ } else if(((hx-0x3ff00000)|__LO(u))==0) {
+ return 0.0; /* acosh(1) = 0 */
+ } else if (hx > 0x40000000) { /* 2**28 > x > 2 */
+ t=x*x;
+ return __ieee754_log(2.0*x-one/(x+fd_sqrt(t-one)));
+ } else { /* 1<x<2 */
+ t = x-one;
+ return fd_log1p(t+fd_sqrt(2.0*t+t*t));
+ }
+}
diff --git a/src/dom/js/fdlibm/e_asin.c b/src/dom/js/fdlibm/e_asin.c
new file mode 100644
index 000000000..624c4d2ce
--- /dev/null
+++ b/src/dom/js/fdlibm/e_asin.c
@@ -0,0 +1,156 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_asin(x)
+ * Method :
+ * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ * we approximate asin(x) on [0,0.5] by
+ * asin(x) = x + x*x^2*R(x^2)
+ * where
+ * R(x^2) is a rational approximation of (asin(x)-x)/x^3
+ * and its remez error is bounded by
+ * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ * For x in [0.5,1]
+ * asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ * then for x>0.98
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ * For x<=0.98, let pio4_hi = pio2_hi/2, then
+ * f = hi part of s;
+ * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z)
+ * and
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+really_big = 1.000e+300,
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+ /* coefficient for R(x^2) */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+#ifdef __STDC__
+ double __ieee754_asin(double x)
+#else
+ double __ieee754_asin(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double w,t,p,q,c,r,s;
+ int hx,ix;
+ u.d = x;
+ hx = __HI(u);
+ x = u.d;
+ ix = hx&0x7fffffff;
+ if(ix>= 0x3ff00000) { /* |x|>= 1 */
+ if(((ix-0x3ff00000)|__LO(u))==0)
+ /* asin(1)=+-pi/2 with inexact */
+ return x*pio2_hi+x*pio2_lo;
+ return (x-x)/(x-x); /* asin(|x|>1) is NaN */
+ } else if (ix<0x3fe00000) { /* |x|<0.5 */
+ if(ix<0x3e400000) { /* if |x| < 2**-27 */
+ if(really_big+x>one) return x;/* return x with inexact if x!=0*/
+ } else
+ t = x*x;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ w = p/q;
+ return x+x*w;
+ }
+ /* 1> |x|>= 0.5 */
+ w = one-fd_fabs(x);
+ t = w*0.5;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ s = fd_sqrt(t);
+ if(ix>=0x3FEF3333) { /* if |x| > 0.975 */
+ w = p/q;
+ t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+ } else {
+ u.d = s;
+ __LO(u) = 0;
+ w = u.d;
+ c = (t-w*w)/(s+w);
+ r = p/q;
+ p = 2.0*s*r-(pio2_lo-2.0*c);
+ q = pio4_hi-2.0*w;
+ t = pio4_hi-(p-q);
+ }
+ if(hx>0) return t; else return -t;
+}
diff --git a/src/dom/js/fdlibm/e_atan2.c b/src/dom/js/fdlibm/e_atan2.c
new file mode 100644
index 000000000..9c9a2c01f
--- /dev/null
+++ b/src/dom/js/fdlibm/e_atan2.c
@@ -0,0 +1,165 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atan2(y,x)
+ * Method :
+ * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ * 2. Reduce x to positive by (if x and y are unexceptional):
+ * ARG (x+iy) = arctan(y/x) ... if x > 0,
+ * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0,
+ *
+ * Special cases:
+ *
+ * ATAN2((anything), NaN ) is NaN;
+ * ATAN2(NAN , (anything) ) is NaN;
+ * ATAN2(+-0, +(anything but NaN)) is +-0 ;
+ * ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ * ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ * ATAN2(+-INF,+INF ) is +-pi/4 ;
+ * ATAN2(+-INF,-INF ) is +-3pi/4;
+ * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+tiny = 1.0e-300,
+zero = 0.0,
+pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+#ifdef __STDC__
+ double __ieee754_atan2(double y, double x)
+#else
+ double __ieee754_atan2(y,x)
+ double y,x;
+#endif
+{
+ fd_twoints ux, uy, uz;
+ double z;
+ int k,m,hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ ux.d = x; uy.d = y;
+ hx = __HI(ux); ix = hx&0x7fffffff;
+ lx = __LO(ux);
+ hy = __HI(uy); iy = hy&0x7fffffff;
+ ly = __LO(uy);
+ if(((ix|((lx|-(int)lx)>>31))>0x7ff00000)||
+ ((iy|((ly|-(int)ly)>>31))>0x7ff00000)) /* x or y is NaN */
+ return x+y;
+ if(((hx-0x3ff00000)|lx)==0) return fd_atan(y); /* x=1.0 */
+ m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */
+
+ /* when y = 0 */
+ if((iy|ly)==0) {
+ switch(m) {
+ case 0:
+ case 1: return y; /* atan(+-0,+anything)=+-0 */
+ case 2: return pi+tiny;/* atan(+0,-anything) = pi */
+ case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+ }
+ }
+ /* when x = 0 */
+ if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* when x is INF */
+ if(ix==0x7ff00000) {
+ if(iy==0x7ff00000) {
+ switch(m) {
+ case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */
+ case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+ case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+ case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+ }
+ } else {
+ switch(m) {
+ case 0: return zero ; /* atan(+...,+INF) */
+ case 1: return -zero ; /* atan(-...,+INF) */
+ case 2: return pi+tiny ; /* atan(+...,-INF) */
+ case 3: return -pi-tiny ; /* atan(-...,-INF) */
+ }
+ }
+ }
+ /* when y is INF */
+ if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* compute y/x */
+ k = (iy-ix)>>20;
+ if(k > 60) z=pi_o_2+0.5*pi_lo; /* |y/x| > 2**60 */
+ else if(hx<0&&k<-60) z=0.0; /* |y|/x < -2**60 */
+ else z=fd_atan(fd_fabs(y/x)); /* safe to do y/x */
+ switch (m) {
+ case 0: return z ; /* atan(+,+) */
+ case 1: uz.d = z;
+ __HI(uz) ^= 0x80000000;
+ z = uz.d;
+ return z ; /* atan(-,+) */
+ case 2: return pi-(z-pi_lo);/* atan(+,-) */
+ default: /* case 3 */
+ return (z-pi_lo)-pi;/* atan(-,-) */
+ }
+}
diff --git a/src/dom/js/fdlibm/e_atanh.c b/src/dom/js/fdlibm/e_atanh.c
new file mode 100644
index 000000000..dc4a90c8e
--- /dev/null
+++ b/src/dom/js/fdlibm/e_atanh.c
@@ -0,0 +1,110 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atanh(x)
+ * Method :
+ * 1.Reduced x to positive by atanh(-x) = -atanh(x)
+ * 2.For x>=0.5
+ * 1 2x x
+ * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ * 2 1 - x 1 - x
+ *
+ * For x<0.5
+ * atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ * atanh(x) is NaN if |x| > 1 with signal;
+ * atanh(NaN) is that NaN with no signal;
+ * atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double one = 1.0, really_big = 1e300;
+#else
+static double one = 1.0, really_big = 1e300;
+#endif
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_atanh(double x)
+#else
+ double __ieee754_atanh(x)
+ double x;
+#endif
+{
+ double t;
+ int hx,ix;
+ unsigned lx;
+ fd_twoints u;
+ u.d = x;
+ hx = __HI(u); /* high word */
+ lx = __LO(u); /* low word */
+ ix = hx&0x7fffffff;
+ if ((ix|((lx|(-(int)lx))>>31))>0x3ff00000) /* |x|>1 */
+ return (x-x)/(x-x);
+ if(ix==0x3ff00000)
+ return x/zero;
+ if(ix<0x3e300000&&(really_big+x)>zero) return x; /* x<2**-28 */
+ u.d = x;
+ __HI(u) = ix; /* x <- |x| */
+ x = u.d;
+ if(ix<0x3fe00000) { /* x < 0.5 */
+ t = x+x;
+ t = 0.5*fd_log1p(t+t*x/(one-x));
+ } else
+ t = 0.5*fd_log1p((x+x)/(one-x));
+ if(hx>=0) return t; else return -t;
+}
diff --git a/src/dom/js/fdlibm/e_cosh.c b/src/dom/js/fdlibm/e_cosh.c
new file mode 100644
index 000000000..4f8d4f769
--- /dev/null
+++ b/src/dom/js/fdlibm/e_cosh.c
@@ -0,0 +1,133 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_cosh(x)
+ * Method :
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ * 1. Replace x by |x| (cosh(x) = cosh(-x)).
+ * 2.
+ * [ exp(x) - 1 ]^2
+ * 0 <= x <= ln2/2 : cosh(x) := 1 + -------------------
+ * 2*exp(x)
+ *
+ * exp(x) + 1/exp(x)
+ * ln2/2 <= x <= 22 : cosh(x) := -------------------
+ * 2
+ * 22 <= x <= lnovft : cosh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : cosh(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ * cosh(x) is |x| if x is +INF, -INF, or NaN.
+ * only cosh(0)=1 is exact for finite x.
+ */
+
+#include "fdlibm.h"
+
+#ifdef _WIN32
+#define huge myhuge
+#endif
+
+#ifdef __STDC__
+static const double one = 1.0, half=0.5, really_big = 1.0e300;
+#else
+static double one = 1.0, half=0.5, really_big = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_cosh(double x)
+#else
+ double __ieee754_cosh(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double t,w;
+ int ix;
+ unsigned lx;
+
+ /* High word of |x|. */
+ u.d = x;
+ ix = __HI(u);
+ ix &= 0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x*x;
+
+ /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+ if(ix<0x3fd62e43) {
+ t = fd_expm1(fd_fabs(x));
+ w = one+t;
+ if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */
+ return one+(t*t)/(w+w);
+ }
+
+ /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+ if (ix < 0x40360000) {
+ t = __ieee754_exp(fd_fabs(x));
+ return half*t+half/t;
+ }
+
+ /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+ if (ix < 0x40862E42) return half*__ieee754_exp(fd_fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE ||
+ (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+ w = __ieee754_exp(half*fd_fabs(x));
+ t = half*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, cosh(x) overflow */
+ return really_big*really_big;
+}
diff --git a/src/dom/js/fdlibm/e_exp.c b/src/dom/js/fdlibm/e_exp.c
new file mode 100644
index 000000000..ad9cec124
--- /dev/null
+++ b/src/dom/js/fdlibm/e_exp.c
@@ -0,0 +1,202 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_exp.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2.
+ *
+ * Here r will be represented as r = hi-lo for better
+ * accuracy.
+ *
+ * 2. Approximation of exp(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Write
+ * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ * We use a special Reme algorithm on [0,0.34658] to generate
+ * a polynomial of degree 5 to approximate R. The maximum error
+ * of this polynomial approximation is bounded by 2**-59. In
+ * other words,
+ * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ * (where z=r*r, and the values of P1 to P5 are listed below)
+ * and
+ * | 5 | -59
+ * | 2.0+P1*z+...+P5*z - R(z) | <= 2
+ * | |
+ * The computation of exp(r) thus becomes
+ * 2*r
+ * exp(r) = 1 + -------
+ * R - r
+ * r*R1(r)
+ * = 1 + r + ----------- (for better accuracy)
+ * 2 - R1(r)
+ * where
+ * 2 4 10
+ * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+ *
+ * 3. Scale back to obtain exp(x):
+ * From step 1, we have
+ * exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF) is 0, and
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then exp(x) overflow
+ * if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+halF[2] = {0.5,-0.5,},
+really_big = 1.0e+300,
+twom1000= 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */
+ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
+ -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
+ -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+#ifdef __STDC__
+ double __ieee754_exp(double x) /* default IEEE double exp */
+#else
+ double __ieee754_exp(x) /* default IEEE double exp */
+ double x;
+#endif
+{
+ fd_twoints u;
+ double y,hi,lo,c,t;
+ int k, xsb;
+ unsigned hx;
+
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ xsb = (hx>>31)&1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ u.d = x;
+ if(((hx&0xfffff)|__LO(u))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */
+ }
+ if(x > o_threshold) return really_big*really_big; /* overflow */
+ if(x < u_threshold) return twom1000*twom1000; /* underflow */
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+ } else {
+ k = (int)(invln2*x+halF[xsb]);
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ }
+ else if(hx < 0x3e300000) { /* when |x|<2**-28 */
+ if(really_big+x>one) return one+x;/* trigger inexact */
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ t = x*x;
+ c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ if(k==0) return one-((x*c)/(c-2.0)-x);
+ else y = one-((lo-(x*c)/(2.0-c))-hi);
+ if(k >= -1021) {
+ u.d = y;
+ __HI(u) += (k<<20); /* add k to y's exponent */
+ y = u.d;
+ return y;
+ } else {
+ u.d = y;
+ __HI(u) += ((k+1000)<<20);/* add k to y's exponent */
+ y = u.d;
+ return y*twom1000;
+ }
+}
diff --git a/src/dom/js/fdlibm/e_fmod.c b/src/dom/js/fdlibm/e_fmod.c
new file mode 100644
index 000000000..7b5ce780f
--- /dev/null
+++ b/src/dom/js/fdlibm/e_fmod.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+#else
+static double one = 1.0, Zero[] = {0.0, -0.0,};
+#endif
+
+#ifdef __STDC__
+ double __ieee754_fmod(double x, double y)
+#else
+ double __ieee754_fmod(x,y)
+ double x,y ;
+#endif
+{
+ fd_twoints ux, uy;
+ int n,hx,hy,hz,ix,iy,sx,i;
+ unsigned lx,ly,lz;
+
+ ux.d = x; uy.d = y;
+ hx = __HI(ux); /* high word of x */
+ lx = __LO(ux); /* low word of x */
+ hy = __HI(uy); /* high word of y */
+ ly = __LO(uy); /* low word of y */
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */
+ ((hy|((ly|-(int)ly)>>31))>0x7ff00000)) /* or y is NaN */
+ return (x*y)/(x*y);
+ if(hx<=hy) {
+ if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
+ if(lx==ly)
+ return Zero[(unsigned)sx>>31]; /* |x|=|y| return x*0*/
+ }
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00100000) { /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+ } else {
+ for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+ }
+ } else ix = (hx>>20)-1023;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00100000) { /* subnormal y */
+ if(hy==0) {
+ for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+ } else {
+ for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+ }
+ } else iy = (hy>>20)-1023;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -1022)
+ hx = 0x00100000|(0x000fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -1022-ix;
+ if(n<=31) {
+ hx = (hx<<n)|(lx>>(32-n));
+ lx <<= n;
+ } else {
+ hx = lx<<(n-32);
+ lx = 0;
+ }
+ }
+ if(iy >= -1022)
+ hy = 0x00100000|(0x000fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -1022-iy;
+ if(n<=31) {
+ hy = (hy<<n)|(ly>>(32-n));
+ ly <<= n;
+ } else {
+ hy = ly<<(n-32);
+ ly = 0;
+ }
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ while(n--) {
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+ else {
+ if((hz|lz)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ hx = hz+hz+(lz>>31); lx = lz+lz;
+ }
+ }
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz>=0) {hx=hz;lx=lz;}
+
+ /* convert back to floating value and restore the sign */
+ if((hx|lx)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ while(hx<0x00100000) { /* normalize x */
+ hx = hx+hx+(lx>>31); lx = lx+lx;
+ iy -= 1;
+ }
+ if(iy>= -1022) { /* normalize output */
+ hx = ((hx-0x00100000)|((iy+1023)<<20));
+ ux.d = x;
+ __HI(ux) = hx|sx;
+ __LO(ux) = lx;
+ x = ux.d;
+ } else { /* subnormal output */
+ n = -1022 - iy;
+ if(n<=20) {
+ lx = (lx>>n)|((unsigned)hx<<(32-n));
+ hx >>= n;
+ } else if (n<=31) {
+ lx = (hx<<(32-n))|(lx>>n); hx = sx;
+ } else {
+ lx = hx>>(n-32); hx = sx;
+ }
+ ux.d = x;
+ __HI(ux) = hx|sx;
+ __LO(ux) = lx;
+ x = ux.d;
+ x *= one; /* create necessary signal */
+ }
+ return x; /* exact output */
+}
diff --git a/src/dom/js/fdlibm/e_gamma.c b/src/dom/js/fdlibm/e_gamma.c
new file mode 100644
index 000000000..a34faa32c
--- /dev/null
+++ b/src/dom/js/fdlibm/e_gamma.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_gamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_gamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_gamma_r
+ */
+
+#include "fdlibm.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double __ieee754_gamma(double x)
+#else
+ double __ieee754_gamma(x)
+ double x;
+#endif
+{
+ return __ieee754_gamma_r(x,&signgam);
+}
diff --git a/src/dom/js/fdlibm/e_gamma_r.c b/src/dom/js/fdlibm/e_gamma_r.c
new file mode 100644
index 000000000..f10e32e36
--- /dev/null
+++ b/src/dom/js/fdlibm/e_gamma_r.c
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_gamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_gamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method: See __ieee754_lgamma_r
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double __ieee754_gamma_r(double x, int *signgamp)
+#else
+ double __ieee754_gamma_r(x,signgamp)
+ double x; int *signgamp;
+#endif
+{
+ return __ieee754_lgamma_r(x,signgamp);
+}
diff --git a/src/dom/js/fdlibm/e_hypot.c b/src/dom/js/fdlibm/e_hypot.c
new file mode 100644
index 000000000..390023087
--- /dev/null
+++ b/src/dom/js/fdlibm/e_hypot.c
@@ -0,0 +1,173 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_hypot(x,y)
+ *
+ * Method :
+ * If (assume round-to-nearest) z=x*x+y*y
+ * has error less than sqrt(2)/2 ulp, than
+ * sqrt(z) has error less than 1 ulp (exercise).
+ *
+ * So, compute sqrt(x*x+y*y) with some care as
+ * follows to get the error below 1 ulp:
+ *
+ * Assume x>y>0;
+ * (if possible, set rounding to round-to-nearest)
+ * 1. if x > 2y use
+ * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ * where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ * 2. if x <= 2y use
+ * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
+ * y1= y with lower 32 bits chopped, y2 = y-y1.
+ *
+ * NOTE: scaling may be necessary if some argument is too
+ * large or too tiny
+ *
+ * Special cases:
+ * hypot(x,y) is INF if x or y is +INF or -INF; else
+ * hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ * hypot(x,y) returns sqrt(x^2+y^2) with error less
+ * than 1 ulps (units in the last place)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double __ieee754_hypot(double x, double y)
+#else
+ double __ieee754_hypot(x,y)
+ double x, y;
+#endif
+{
+ fd_twoints ux, uy;
+ double a=x,b=y,t1,t2,y1,y2,w;
+ int j,k,ha,hb;
+
+ ux.d = x; uy.d = y;
+ ha = __HI(ux)&0x7fffffff; /* high word of x */
+ hb = __HI(uy)&0x7fffffff; /* high word of y */
+ if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+ ux.d = a; uy.d = b;
+ __HI(ux) = ha; /* a <- |a| */
+ __HI(uy) = hb; /* b <- |b| */
+ a = ux.d; b = uy.d;
+ if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+ k=0;
+ if(ha > 0x5f300000) { /* a>2**500 */
+ if(ha >= 0x7ff00000) { /* Inf or NaN */
+ w = a+b; /* for sNaN */
+ ux.d = a; uy.d = b;
+ if(((ha&0xfffff)|__LO(ux))==0) w = a;
+ if(((hb^0x7ff00000)|__LO(uy))==0) w = b;
+ return w;
+ }
+ /* scale a and b by 2**-600 */
+ ha -= 0x25800000; hb -= 0x25800000; k += 600;
+ ux.d = a; uy.d = b;
+ __HI(ux) = ha;
+ __HI(uy) = hb;
+ a = ux.d; b = uy.d;
+ }
+ if(hb < 0x20b00000) { /* b < 2**-500 */
+ if(hb <= 0x000fffff) { /* subnormal b or 0 */
+ uy.d = b;
+ if((hb|(__LO(uy)))==0) return a;
+ t1=0;
+ ux.d = t1;
+ __HI(ux) = 0x7fd00000; /* t1=2^1022 */
+ t1 = ux.d;
+ b *= t1;
+ a *= t1;
+ k -= 1022;
+ } else { /* scale a and b by 2^600 */
+ ha += 0x25800000; /* a *= 2^600 */
+ hb += 0x25800000; /* b *= 2^600 */
+ k -= 600;
+ ux.d = a; uy.d = b;
+ __HI(ux) = ha;
+ __HI(uy) = hb;
+ a = ux.d; b = uy.d;
+ }
+ }
+ /* medium size a and b */
+ w = a-b;
+ if (w>b) {
+ t1 = 0;
+ ux.d = t1;
+ __HI(ux) = ha;
+ t1 = ux.d;
+ t2 = a-t1;
+ w = fd_sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+ } else {
+ a = a+a;
+ y1 = 0;
+ ux.d = y1;
+ __HI(ux) = hb;
+ y1 = ux.d;
+ y2 = b - y1;
+ t1 = 0;
+ ux.d = t1;
+ __HI(ux) = ha+0x00100000;
+ t1 = ux.d;
+ t2 = a - t1;
+ w = fd_sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+ }
+ if(k!=0) {
+ t1 = 1.0;
+ ux.d = t1;
+ __HI(ux) += (k<<20);
+ t1 = ux.d;
+ return t1*w;
+ } else return w;
+}
diff --git a/src/dom/js/fdlibm/e_j0.c b/src/dom/js/fdlibm/e_j0.c
new file mode 100644
index 000000000..078e09641
--- /dev/null
+++ b/src/dom/js/fdlibm/e_j0.c
@@ -0,0 +1,524 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j0(x), __ieee754_y0(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j0(x):
+ * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
+ * 2. Reduce x to |x| since j0(x)=j0(-x), and
+ * for x in (0,2)
+ * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x;
+ * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
+ * for x in (2,inf)
+ * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * as follow:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (cos(x) + sin(x))
+ * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j0(nan)= nan
+ * j0(0) = 1
+ * j0(inf) = 0
+ *
+ * Method -- y0(x):
+ * 1. For x<2.
+ * Since
+ * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
+ * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+ * We use the following function to approximate y0,
+ * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
+ * where
+ * U(z) = u00 + u01*z + ... + u06*z^6
+ * V(z) = 1 + v01*z + ... + v04*z^4
+ * with absolute approximation error bounded by 2**-72.
+ * Note: For tiny x, U/V = u0 and j0(x)~1, hence
+ * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+ * 2. For x>=2.
+ * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * by the method mentioned above.
+ * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static double pzero(double), qzero(double);
+#else
+static double pzero(), qzero();
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+really_big = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0, 2.00] */
+R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */
+R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */
+R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */
+R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */
+S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */
+S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
+S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
+S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_j0(double x)
+#else
+ double __ieee754_j0(x)
+ double x;
+#endif
+{
+ fd_twoints un;
+ double z, s,c,ss,cc,r,u,v;
+ int hx,ix;
+
+ un.d = x;
+ hx = __HI(un);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/(x*x);
+ x = fd_fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = fd_sin(x);
+ c = fd_cos(x);
+ ss = s-c;
+ cc = s+c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -fd_cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/fd_sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*cc-v*ss)/fd_sqrt(x);
+ }
+ return z;
+ }
+ if(ix<0x3f200000) { /* |x| < 2**-13 */
+ if(really_big+x>one) { /* raise inexact if x != 0 */
+ if(ix<0x3e400000) return one; /* |x|<2**-27 */
+ else return one - 0.25*x*x;
+ }
+ }
+ z = x*x;
+ r = z*(R02+z*(R03+z*(R04+z*R05)));
+ s = one+z*(S01+z*(S02+z*(S03+z*S04)));
+ if(ix < 0x3FF00000) { /* |x| < 1.00 */
+ return one + z*(-0.25+(r/s));
+ } else {
+ u = 0.5*x;
+ return((one+u)*(one-u)+z*(r/s));
+ }
+}
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */
+u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */
+u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */
+u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */
+u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */
+u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */
+u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */
+v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */
+v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
+v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
+v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
+
+#ifdef __STDC__
+ double __ieee754_y0(double x)
+#else
+ double __ieee754_y0(x)
+ double x;
+#endif
+{
+ fd_twoints un;
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ un.d = x;
+ hx = __HI(un);
+ ix = 0x7fffffff&hx;
+ lx = __LO(un);
+ /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ * where x0 = x-pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) + cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ s = fd_sin(x);
+ c = fd_cos(x);
+ ss = s-c;
+ cc = s+c;
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -fd_cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ if(ix>0x48000000) z = (invsqrtpi*ss)/fd_sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*ss+v*cc)/fd_sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3e400000) { /* x < 2**-27 */
+ return(u00 + tpi*__ieee754_log(x));
+ }
+ z = x*x;
+ u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+ v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+ return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ * pzero(x) = 1 + (R/S)
+ * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ * S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ * | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+ */
+#ifdef __STDC__
+static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
+ -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
+ -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
+ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
+ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
+};
+#ifdef __STDC__
+static const double pS8[5] = {
+#else
+static double pS8[5] = {
+#endif
+ 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
+ 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
+ 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
+ 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
+ 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
+};
+
+#ifdef __STDC__
+static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
+ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
+ -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
+ -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
+ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
+ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
+};
+#ifdef __STDC__
+static const double pS5[5] = {
+#else
+static double pS5[5] = {
+#endif
+ 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
+ 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
+ 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
+ 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
+ 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
+};
+
+#ifdef __STDC__
+static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#else
+static double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
+ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
+ -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
+ -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
+ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
+ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
+};
+#ifdef __STDC__
+static const double pS3[5] = {
+#else
+static double pS3[5] = {
+#endif
+ 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
+ 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
+ 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
+ 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
+ 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
+};
+
+#ifdef __STDC__
+static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
+ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
+ -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
+ -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
+ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
+ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
+};
+#ifdef __STDC__
+static const double pS2[5] = {
+#else
+static double pS2[5] = {
+#endif
+ 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
+ 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
+ 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
+ 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
+ 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
+};
+
+#ifdef __STDC__
+ static double pzero(double x)
+#else
+ static double pzero(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ fd_twoints u;
+ double z,r,s;
+ int ix;
+ u.d = x;
+ ix = 0x7fffffff&__HI(u);
+ if(ix>=0x40200000) {p = pR8; q= pS8;}
+ else if(ix>=0x40122E8B){p = pR5; q= pS5;}
+ else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
+ else if(ix>=0x40000000){p = pR2; q= pS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ * -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ * qzero(x) = s*(-1.25 + (R/S))
+ * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ * S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22)
+ */
+#ifdef __STDC__
+static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
+ 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
+ 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
+ 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
+ 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
+};
+#ifdef __STDC__
+static const double qS8[6] = {
+#else
+static double qS8[6] = {
+#endif
+ 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
+ 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
+ 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
+ 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
+ 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
+ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
+};
+
+#ifdef __STDC__
+static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
+ 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
+ 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
+ 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
+ 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
+ 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
+};
+#ifdef __STDC__
+static const double qS5[6] = {
+#else
+static double qS5[6] = {
+#endif
+ 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
+ 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
+ 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
+ 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
+ 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
+ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
+};
+
+#ifdef __STDC__
+static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#else
+static double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
+ 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
+ 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
+ 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
+ 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
+ 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
+};
+#ifdef __STDC__
+static const double qS3[6] = {
+#else
+static double qS3[6] = {
+#endif
+ 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
+ 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
+ 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
+ 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
+ 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
+ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
+};
+
+#ifdef __STDC__
+static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
+ 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
+ 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
+ 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
+ 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
+ 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
+};
+#ifdef __STDC__
+static const double qS2[6] = {
+#else
+static double qS2[6] = {
+#endif
+ 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
+ 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
+ 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
+ 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
+ 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
+ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
+};
+
+#ifdef __STDC__
+ static double qzero(double x)
+#else
+ static double qzero(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ fd_twoints u;
+ double s,r,z;
+ int ix;
+ u.d = x;
+ ix = 0x7fffffff&__HI(u);
+ if(ix>=0x40200000) {p = qR8; q= qS8;}
+ else if(ix>=0x40122E8B){p = qR5; q= qS5;}
+ else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
+ else if(ix>=0x40000000){p = qR2; q= qS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (-.125 + r/s)/x;
+}
diff --git a/src/dom/js/fdlibm/e_j1.c b/src/dom/js/fdlibm/e_j1.c
new file mode 100644
index 000000000..8982ac86a
--- /dev/null
+++ b/src/dom/js/fdlibm/e_j1.c
@@ -0,0 +1,523 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j1(x), __ieee754_y1(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j1(x):
+ * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
+ * 2. Reduce x to |x| since j1(x)=-j1(-x), and
+ * for x in (0,2)
+ * j1(x) = x/2 + x*z*R0/S0, where z = x*x;
+ * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+ * for x in (2,inf)
+ * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * as follow:
+ * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (sin(x) + cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j1(nan)= nan
+ * j1(0) = 0
+ * j1(inf) = 0
+ *
+ * Method -- y1(x):
+ * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+ * 2. For x<2.
+ * Since
+ * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...)
+ * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+ * We use the following function to approximate y1,
+ * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2
+ * where for x in [0,2] (abs err less than 2**-65.89)
+ * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4
+ * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5
+ * Note: For tiny x, 1/x dominate y1 and hence
+ * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+ * 3. For x>=2.
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * by method mentioned above.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static double pone(double), qone(double);
+#else
+static double pone(), qone();
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+really_big = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0,2] */
+r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */
+r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */
+r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */
+r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */
+s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */
+s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */
+s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
+s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
+s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_j1(double x)
+#else
+ double __ieee754_j1(x)
+ double x;
+#endif
+{
+ fd_twoints un;
+ double z, s,c,ss,cc,r,u,v,y;
+ int hx,ix;
+
+ un.d = x;
+ hx = __HI(un);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/x;
+ y = fd_fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = fd_sin(y);
+ c = fd_cos(y);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure y+y not overflow */
+ z = fd_cos(y+y);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/fd_sqrt(y);
+ else {
+ u = pone(y); v = qone(y);
+ z = invsqrtpi*(u*cc-v*ss)/fd_sqrt(y);
+ }
+ if(hx<0) return -z;
+ else return z;
+ }
+ if(ix<0x3e400000) { /* |x|<2**-27 */
+ if(really_big+x>one) return 0.5*x;/* inexact if x!=0 necessary */
+ }
+ z = x*x;
+ r = z*(r00+z*(r01+z*(r02+z*r03)));
+ s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+ r *= x;
+ return(x*0.5+r/s);
+}
+
+#ifdef __STDC__
+static const double U0[5] = {
+#else
+static double U0[5] = {
+#endif
+ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */
+ 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */
+ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */
+ 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */
+ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */
+};
+#ifdef __STDC__
+static const double V0[5] = {
+#else
+static double V0[5] = {
+#endif
+ 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */
+ 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */
+ 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */
+ 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */
+ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
+};
+
+#ifdef __STDC__
+ double __ieee754_y1(double x)
+#else
+ double __ieee754_y1(x)
+ double x;
+#endif
+{
+ fd_twoints un;
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ un.d = x;
+ hx = __HI(un);
+ ix = 0x7fffffff&hx;
+ lx = __LO(un);
+ /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = fd_sin(x);
+ c = fd_cos(x);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = fd_cos(x+x);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ * where x0 = x-3pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (cos(x) + sin(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ if(ix>0x48000000) z = (invsqrtpi*ss)/fd_sqrt(x);
+ else {
+ u = pone(x); v = qone(x);
+ z = invsqrtpi*(u*ss+v*cc)/fd_sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3c900000) { /* x < 2**-54 */
+ return(-tpi/x);
+ }
+ z = x*x;
+ u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+ v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+ return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x.
+ * We approximate pone by
+ * pone(x) = 1 + (R/S)
+ * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ * S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ * | pone(x)-1-R/S | <= 2 ** ( -60.06)
+ */
+
+#ifdef __STDC__
+static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */
+ 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */
+ 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */
+ 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */
+ 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */
+};
+#ifdef __STDC__
+static const double ps8[5] = {
+#else
+static double ps8[5] = {
+#endif
+ 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */
+ 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */
+ 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */
+ 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */
+ 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */
+};
+
+#ifdef __STDC__
+static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */
+ 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */
+ 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */
+ 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */
+ 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */
+ 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */
+};
+#ifdef __STDC__
+static const double ps5[5] = {
+#else
+static double ps5[5] = {
+#endif
+ 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */
+ 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */
+ 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */
+ 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */
+ 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */
+};
+
+#ifdef __STDC__
+static const double pr3[6] = {
+#else
+static double pr3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */
+ 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */
+ 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */
+ 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */
+ 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */
+ 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */
+};
+#ifdef __STDC__
+static const double ps3[5] = {
+#else
+static double ps3[5] = {
+#endif
+ 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */
+ 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */
+ 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */
+ 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */
+ 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */
+};
+
+#ifdef __STDC__
+static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */
+ 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */
+ 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */
+ 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */
+ 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */
+ 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */
+};
+#ifdef __STDC__
+static const double ps2[5] = {
+#else
+static double ps2[5] = {
+#endif
+ 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */
+ 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */
+ 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */
+ 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */
+ 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
+};
+
+#ifdef __STDC__
+ static double pone(double x)
+#else
+ static double pone(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ fd_twoints un;
+ double z,r,s;
+ int ix;
+ un.d = x;
+ ix = 0x7fffffff&__HI(un);
+ if(ix>=0x40200000) {p = pr8; q= ps8;}
+ else if(ix>=0x40122E8B){p = pr5; q= ps5;}
+ else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
+ else if(ix>=0x40000000){p = pr2; q= ps2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qone is
+ * 3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ * qone(x) = s*(0.375 + (R/S))
+ * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ * S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13)
+ */
+
+#ifdef __STDC__
+static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */
+ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */
+ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */
+ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */
+ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */
+};
+#ifdef __STDC__
+static const double qs8[6] = {
+#else
+static double qs8[6] = {
+#endif
+ 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */
+ 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */
+ 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */
+ 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */
+ 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */
+ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */
+};
+
+#ifdef __STDC__
+static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */
+ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */
+ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */
+ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */
+ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */
+ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */
+};
+#ifdef __STDC__
+static const double qs5[6] = {
+#else
+static double qs5[6] = {
+#endif
+ 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */
+ 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */
+ 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */
+ 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */
+ 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */
+ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */
+};
+
+#ifdef __STDC__
+static const double qr3[6] = {
+#else
+static double qr3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */
+ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */
+ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */
+ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */
+ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */
+ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */
+};
+#ifdef __STDC__
+static const double qs3[6] = {
+#else
+static double qs3[6] = {
+#endif
+ 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */
+ 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */
+ 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */
+ 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */
+ 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */
+ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */
+};
+
+#ifdef __STDC__
+static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */
+ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */
+ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */
+ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */
+ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */
+ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */
+};
+#ifdef __STDC__
+static const double qs2[6] = {
+#else
+static double qs2[6] = {
+#endif
+ 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */
+ 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */
+ 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */
+ 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */
+ 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */
+ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
+};
+
+#ifdef __STDC__
+ static double qone(double x)
+#else
+ static double qone(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ fd_twoints un;
+ double s,r,z;
+ int ix;
+ un.d = x;
+ ix = 0x7fffffff&__HI(un);
+ if(ix>=0x40200000) {p = qr8; q= qs8;}
+ else if(ix>=0x40122E8B){p = qr5; q= qs5;}
+ else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
+ else if(ix>=0x40000000){p = qr2; q= qs2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (.375 + r/s)/x;
+}
diff --git a/src/dom/js/fdlibm/e_jn.c b/src/dom/js/fdlibm/e_jn.c
new file mode 100644
index 000000000..2b61b4439
--- /dev/null
+++ b/src/dom/js/fdlibm/e_jn.c
@@ -0,0 +1,315 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_jn.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
+
+static double zero = 0.00000000000000000000e+00;
+
+#ifdef __STDC__
+ double __ieee754_jn(int n, double x)
+#else
+ double __ieee754_jn(n,x)
+ int n; double x;
+#endif
+{
+ fd_twoints u;
+ int i,hx,ix,lx, sgn;
+ double a, b, temp, di;
+ double z, w;
+
+ /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+ * Thus, J(-n,x) = J(n,-x)
+ */
+ u.d = x;
+ hx = __HI(u);
+ ix = 0x7fffffff&hx;
+ lx = __LO(u);
+ /* if J(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if(n<0){
+ n = -n;
+ x = -x;
+ hx ^= 0x80000000;
+ }
+ if(n==0) return(__ieee754_j0(x));
+ if(n==1) return(__ieee754_j1(x));
+ sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */
+ x = fd_fabs(x);
+ if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */
+ b = zero;
+ else if((double)n<=x) {
+ /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = fd_cos(x)+fd_sin(x); break;
+ case 1: temp = -fd_cos(x)+fd_sin(x); break;
+ case 2: temp = -fd_cos(x)-fd_sin(x); break;
+ case 3: temp = fd_cos(x)-fd_sin(x); break;
+ }
+ b = invsqrtpi*temp/fd_sqrt(x);
+ } else {
+ a = __ieee754_j0(x);
+ b = __ieee754_j1(x);
+ for(i=1;i<n;i++){
+ temp = b;
+ b = b*((double)(i+i)/x) - a; /* avoid underflow */
+ a = temp;
+ }
+ }
+ } else {
+ if(ix<0x3e100000) { /* x < 2**-29 */
+ /* x is tiny, return the first Taylor expansion of J(n,x)
+ * J(n,x) = 1/n!*(x/2)^n - ...
+ */
+ if(n>33) /* underflow */
+ b = zero;
+ else {
+ temp = x*0.5; b = temp;
+ for (a=one,i=2;i<=n;i++) {
+ a *= (double)i; /* a = n! */
+ b *= temp; /* b = (x/2)^n */
+ }
+ b = b/a;
+ }
+ } else {
+ /* use backward recurrence */
+ /* x x^2 x^2
+ * J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ * 2n - 2(n+1) - 2(n+2)
+ *
+ * 1 1 1
+ * (for large x) = ---- ------ ------ .....
+ * 2n 2(n+1) 2(n+2)
+ * -- - ------ - ------ -
+ * x x x
+ *
+ * Let w = 2n/x and h=2/x, then the above quotient
+ * is equal to the continued fraction:
+ * 1
+ * = -----------------------
+ * 1
+ * w - -----------------
+ * 1
+ * w+h - ---------
+ * w+2h - ...
+ *
+ * To determine how many terms needed, let
+ * Q(0) = w, Q(1) = w(w+h) - 1,
+ * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ * When Q(k) > 1e4 good for single
+ * When Q(k) > 1e9 good for double
+ * When Q(k) > 1e17 good for quadruple
+ */
+ /* determine k */
+ double t,v;
+ double q0,q1,h,tmp; int k,m;
+ w = (n+n)/(double)x; h = 2.0/(double)x;
+ q0 = w; z = w+h; q1 = w*z - 1.0; k=1;
+ while(q1<1.0e9) {
+ k += 1; z += h;
+ tmp = z*q1 - q0;
+ q0 = q1;
+ q1 = tmp;
+ }
+ m = n+n;
+ for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+ a = t;
+ b = one;
+ /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+ * Hence, if n*(log(2n/x)) > ...
+ * single 8.8722839355e+01
+ * double 7.09782712893383973096e+02
+ * long double 1.1356523406294143949491931077970765006170e+04
+ * then recurrent value may overflow and the result is
+ * likely underflow to zero
+ */
+ tmp = n;
+ v = two/x;
+ tmp = tmp*__ieee754_log(fd_fabs(v*tmp));
+ if(tmp<7.09782712893383973096e+02) {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ }
+ } else {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ /* scale b to avoid spurious overflow */
+ if(b>1e100) {
+ a /= b;
+ t /= b;
+ b = one;
+ }
+ }
+ }
+ b = (t*__ieee754_j0(x)/b);
+ }
+ }
+ if(sgn==1) return -b; else return b;
+}
+
+#ifdef __STDC__
+ double __ieee754_yn(int n, double x)
+#else
+ double __ieee754_yn(n,x)
+ int n; double x;
+#endif
+{
+ fd_twoints u;
+ int i,hx,ix,lx;
+ int sign;
+ double a, b, temp;
+
+ u.d = x;
+ hx = __HI(u);
+ ix = 0x7fffffff&hx;
+ lx = __LO(u);
+ /* if Y(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ sign = 1;
+ if(n<0){
+ n = -n;
+ sign = 1 - ((n&1)<<1);
+ }
+ if(n==0) return(__ieee754_y0(x));
+ if(n==1) return(sign*__ieee754_y1(x));
+ if(ix==0x7ff00000) return zero;
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = fd_sin(x)-fd_cos(x); break;
+ case 1: temp = -fd_sin(x)-fd_cos(x); break;
+ case 2: temp = -fd_sin(x)+fd_cos(x); break;
+ case 3: temp = fd_sin(x)+fd_cos(x); break;
+ }
+ b = invsqrtpi*temp/fd_sqrt(x);
+ } else {
+ a = __ieee754_y0(x);
+ b = __ieee754_y1(x);
+ /* quit if b is -inf */
+ u.d = b;
+ for(i=1;i<n&&(__HI(u) != 0xfff00000);i++){
+ temp = b;
+ b = ((double)(i+i)/x)*b - a;
+ a = temp;
+ }
+ }
+ if(sign>0) return b; else return -b;
+}
diff --git a/src/dom/js/fdlibm/e_lgamma.c b/src/dom/js/fdlibm/e_lgamma.c
new file mode 100644
index 000000000..beb3bd932
--- /dev/null
+++ b/src/dom/js/fdlibm/e_lgamma.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_lgamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_lgamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include "fdlibm.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double __ieee754_lgamma(double x)
+#else
+ double __ieee754_lgamma(x)
+ double x;
+#endif
+{
+ return __ieee754_lgamma_r(x,&signgam);
+}
diff --git a/src/dom/js/fdlibm/e_lgamma_r.c b/src/dom/js/fdlibm/e_lgamma_r.c
new file mode 100644
index 000000000..df92e7a26
--- /dev/null
+++ b/src/dom/js/fdlibm/e_lgamma_r.c
@@ -0,0 +1,347 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ * 1. Argument Reduction for 0 < x <= 8
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * reduce x to a number in [1.5,2.5] by
+ * lgamma(1+s) = log(s) + lgamma(s)
+ * for example,
+ * lgamma(7.3) = log(6.3) + lgamma(6.3)
+ * = log(6.3*5.3) + lgamma(5.3)
+ * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ * 2. Polynomial approximation of lgamma around its
+ * minimun ymin=1.461632144968362245 to maintain monotonicity.
+ * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ * Let z = x-ymin;
+ * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ * where
+ * poly(z) is a 14 degree polynomial.
+ * 2. Rational approximation in the primary interval [2,3]
+ * We use the following approximation:
+ * s = x-2.0;
+ * lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ * with accuracy
+ * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ * Our algorithms are based on the following observation
+ *
+ * zeta(2)-1 2 zeta(3)-1 3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+ * 2 3
+ *
+ * where Euler = 0.5771... is the Euler constant, which is very
+ * close to 0.5.
+ *
+ * 3. For x>=8, we have
+ * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ * (better formula:
+ * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ * Let z = 1/x, then we approximation
+ * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ * by
+ * 3 5 11
+ * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+ * where
+ * |w - f(z)| < 2**-58.74
+ *
+ * 4. For negative x, since (G is gamma function)
+ * -x*G(-x)*G(x) = pi/sin(pi*x),
+ * we have
+ * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * lgamma(x) = log(|Gamma(x)|)
+ * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ * Note: one should avoid compute pi*(-x) directly in the
+ * computation of sin(pi*(-x)).
+ *
+ * 5. Special Cases
+ * lgamma(2+s) ~ s*(1-Euler) for tiny s
+ * lgamma(1)=lgamma(2)=0
+ * lgamma(x) ~ -log(x) for tiny x
+ * lgamma(0) = lgamma(inf) = inf
+ * lgamma(-integer) = +-inf
+ *
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static double zero= 0.00000000000000000000e+00;
+
+#ifdef __STDC__
+ static double sin_pi(double x)
+#else
+ static double sin_pi(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double y,z;
+ int n,ix;
+
+ u.d = x;
+ ix = 0x7fffffff&__HI(u);
+
+ if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
+ y = -x; /* x is assume negative */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = fd_floor(y);
+ if(z!=y) { /* inexact anyway */
+ y *= 0.5;
+ y = 2.0*(y - fd_floor(y)); /* y = |x| mod 2.0 */
+ n = (int) (y*4.0);
+ } else {
+ if(ix>=0x43400000) {
+ y = zero; n = 0; /* y must be even */
+ } else {
+ if(ix<0x43300000) z = y+two52; /* exact */
+ u.d = z;
+ n = __LO(u)&1; /* lower word of z */
+ y = n;
+ n<<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __kernel_sin(pi*y,zero,0); break;
+ case 1:
+ case 2: y = __kernel_cos(pi*(0.5-y),zero); break;
+ case 3:
+ case 4: y = __kernel_sin(pi*(one-y),zero,0); break;
+ case 5:
+ case 6: y = -__kernel_cos(pi*(y-1.5),zero); break;
+ default: y = __kernel_sin(pi*(y-2.0),zero,0); break;
+ }
+ return -y;
+}
+
+
+#ifdef __STDC__
+ double __ieee754_lgamma_r(double x, int *signgamp)
+#else
+ double __ieee754_lgamma_r(x,signgamp)
+ double x; int *signgamp;
+#endif
+{
+ fd_twoints u;
+ double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int i,hx,lx,ix;
+
+ u.d = x;
+ hx = __HI(u);
+ lx = __LO(u);
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ *signgamp = 1;
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x*x;
+ if((ix|lx)==0) return one/zero;
+ if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */
+ if(hx<0) {
+ *signgamp = -1;
+ return -__ieee754_log(-x);
+ } else return -__ieee754_log(x);
+ }
+ if(hx<0) {
+ if(ix>=0x43300000) /* |x|>=2**52, must be -integer */
+ return one/zero;
+ t = sin_pi(x);
+ if(t==zero) return one/zero; /* -integer */
+ nadj = __ieee754_log(pi/fd_fabs(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x40000000) {
+ if(ix<=0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -__ieee754_log(x);
+ if(ix>=0x3FE76944) {y = one-x; i= 0;}
+ else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = zero;
+ if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
+ else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
+ else {y=x-one;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += (p-0.5*y); break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += (tf + p); break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += (-0.5*y + p1/p2);
+ }
+ }
+ else if(ix<0x40200000) { /* x < 8.0 */
+ i = (int)x;
+ t = zero;
+ y = x-(double)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = half*y+p/q;
+ z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+6.0); /* FALLTHRU */
+ case 6: z *= (y+5.0); /* FALLTHRU */
+ case 5: z *= (y+4.0); /* FALLTHRU */
+ case 4: z *= (y+3.0); /* FALLTHRU */
+ case 3: z *= (y+2.0); /* FALLTHRU */
+ r += __ieee754_log(z); break;
+ }
+ /* 8.0 <= x < 2**58 */
+ } else if (ix < 0x43900000) {
+ t = __ieee754_log(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-half)*(t-one)+w;
+ } else
+ /* 2**58 <= x <= inf */
+ r = x*(__ieee754_log(x)-one);
+ if(hx<0) r = nadj - r;
+ return r;
+}
diff --git a/src/dom/js/fdlibm/e_log.c b/src/dom/js/fdlibm/e_log.c
new file mode 100644
index 000000000..8645d6efd
--- /dev/null
+++ b/src/dom/js/fdlibm/e_log.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log(x)
+ * Return the logrithm of x
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * 2. Approximation of log(1+f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
+ * (the values of Lg1 to Lg7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lg1*s +...+Lg7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log(1+f) = f - s*(f - R) (if f is not too large)
+ * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
+ *
+ * 3. Finally, log(x) = k*ln2 + log(1+f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log(x) is NaN with signal if x < 0 (including -INF) ;
+ * log(+INF) is +INF; log(0) is -INF with signal;
+ * log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_log(double x)
+#else
+ double __ieee754_log(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double hfsq,f,s,z,R,w,t1,t2,dk;
+ int k,hx,i,j;
+ unsigned lx;
+
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ lx = __LO(u); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ hx &= 0x000fffff;
+ i = (hx+0x95f64)&0x100000;
+ u.d = x;
+ __HI(u) = hx|(i^0x3ff00000); /* normalize x or x/2 */
+ x = u.d;
+ k += (i>>20);
+ f = x-1.0;
+ if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */
+ if(f==zero) {
+ if(k==0) return zero; else {dk=(double)k;
+ return dk*ln2_hi+dk*ln2_lo;}
+ }
+ R = f*f*(0.5-0.33333333333333333*f);
+ if(k==0) return f-R; else {dk=(double)k;
+ return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+ }
+ s = f/(2.0+f);
+ dk = (double)k;
+ z = s*s;
+ i = hx-0x6147a;
+ w = z*z;
+ j = 0x6b851-hx;
+ t1= w*(Lg2+w*(Lg4+w*Lg6));
+ t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+ i |= j;
+ R = t2+t1;
+ if(i>0) {
+ hfsq=0.5*f*f;
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+ } else {
+ if(k==0) return f-s*(f-R); else
+ return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+ }
+}
diff --git a/src/dom/js/fdlibm/e_log10.c b/src/dom/js/fdlibm/e_log10.c
new file mode 100644
index 000000000..5f88f4b4c
--- /dev/null
+++ b/src/dom/js/fdlibm/e_log10.c
@@ -0,0 +1,134 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log10(x)
+ * Return the base 10 logarithm of x
+ *
+ * Method :
+ * Let log10_2hi = leading 40 bits of log10(2) and
+ * log10_2lo = log10(2) - log10_2hi,
+ * ivln10 = 1/log(10) rounded.
+ * Then
+ * n = ilogb(x),
+ * if(n<0) n = n+1;
+ * x = scalbn(x,-n);
+ * log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ * To guarantee log10(10**n)=n, where 10**n is normal, the rounding
+ * mode must set to Round-to-Nearest.
+ * Note 2:
+ * [1/log(10)] rounded to 53 bits has error .198 ulps;
+ * log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ * log10(x) is NaN with signal if x < 0;
+ * log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ * log10(NaN) is that NaN with no signal;
+ * log10(10**N) = N for N=0,1,...,22.
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following constants.
+ * The decimal values may be used, provided that the compiler will convert
+ * from decimal to binary accurately enough to produce the hexadecimal values
+ * shown.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10 = 4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_log10(double x)
+#else
+ double __ieee754_log10(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double y,z;
+ int i,k,hx;
+ unsigned lx;
+
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ lx = __LO(u); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ i = ((unsigned)k&0x80000000)>>31;
+ hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+ y = (double)(k+i);
+ u.d = x;
+ __HI(u) = hx;
+ x = u.d;
+ z = y*log10_2lo + ivln10*__ieee754_log(x);
+ return z+y*log10_2hi;
+}
diff --git a/src/dom/js/fdlibm/e_pow.c b/src/dom/js/fdlibm/e_pow.c
new file mode 100644
index 000000000..18c8d0695
--- /dev/null
+++ b/src/dom/js/fdlibm/e_pow.c
@@ -0,0 +1,386 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_pow.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ * n
+ * Method: Let x = 2 * (1+f)
+ * 1. Compute and return log2(x) in two pieces:
+ * log2(x) = w1 + w2,
+ * where w1 has 53-24 = 29 bit trailing zeros.
+ * 2. Perform y*log2(x) = n+y' by simulating muti-precision
+ * arithmetic, where |y'|<=0.5.
+ * 3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ * 1. (anything) ** 0 is 1
+ * 2. (anything) ** 1 is itself
+ * 3. (anything) ** NAN is NAN
+ * 4. NAN ** (anything except 0) is NAN
+ * 5. +-(|x| > 1) ** +INF is +INF
+ * 6. +-(|x| > 1) ** -INF is +0
+ * 7. +-(|x| < 1) ** +INF is +0
+ * 8. +-(|x| < 1) ** -INF is +INF
+ * 9. +-1 ** +-INF is NAN
+ * 10. +0 ** (+anything except 0, NAN) is +0
+ * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
+ * 12. +0 ** (-anything except 0, NAN) is +INF
+ * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
+ * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ * 15. +INF ** (+anything except 0,NAN) is +INF
+ * 16. +INF ** (-anything except 0,NAN) is +0
+ * 17. -INF ** (anything) = -0 ** (-anything)
+ * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ * 19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ * pow(x,y) returns x**y nearly rounded. In particular
+ * pow(integer,integer)
+ * always returns the correct integer provided it is
+ * representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+#if defined(_MSC_VER)
+/* Microsoft Compiler */
+#pragma warning( disable : 4723 ) /* disables potential divide by 0 warning */
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero = 0.0,
+one = 1.0,
+two = 2.0,
+two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
+really_big = 1.0e300,
+tiny = 1.0e-300,
+ /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+#ifdef __STDC__
+ double __ieee754_pow(double x, double y)
+#else
+ double __ieee754_pow(x,y)
+ double x, y;
+#endif
+{
+ fd_twoints ux, uy, uz;
+ double y1,t1,p_h,t,z,ax;
+ double z_h,z_l,p_l;
+ double t2,r,s,u,v,w;
+ int i,j,k,yisint,n;
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ ux.d = x; uy.d = y;
+ hx = __HI(ux); lx = __LO(ux);
+ hy = __HI(uy); ly = __LO(uy);
+ ix = hx&0x7fffffff; iy = hy&0x7fffffff;
+
+ /* y==zero: x**0 = 1 */
+ if((iy|ly)==0) return one;
+
+ /* +-NaN return x+y */
+ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+ iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
+ return x+y;
+
+ /* determine if y is an odd int when x < 0
+ * yisint = 0 ... y is not an integer
+ * yisint = 1 ... y is an odd int
+ * yisint = 2 ... y is an even int
+ */
+ yisint = 0;
+ if(hx<0) {
+ if(iy>=0x43400000) yisint = 2; /* even integer y */
+ else if(iy>=0x3ff00000) {
+ k = (iy>>20)-0x3ff; /* exponent */
+ if(k>20) {
+ j = ly>>(52-k);
+ if((j<<(52-k))==(int)ly) yisint = 2-(j&1);
+ } else if(ly==0) {
+ j = iy>>(20-k);
+ if((j<<(20-k))==iy) yisint = 2-(j&1);
+ }
+ }
+ }
+
+ /* special value of y */
+ if(ly==0) {
+ if (iy==0x7ff00000) { /* y is +-inf */
+ if(((ix-0x3ff00000)|lx)==0)
+#ifdef _WIN32
+/* VC++ optimizer reduces y - y to 0 */
+ return y / y;
+#else
+ return y - y; /* inf**+-1 is NaN */
+#endif
+ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+ return (hy>=0)? y: zero;
+ else /* (|x|<1)**-,+inf = inf,0 */
+ return (hy<0)?-y: zero;
+ }
+ if(iy==0x3ff00000) { /* y is +-1 */
+ if(hy<0) return one/x; else return x;
+ }
+ if(hy==0x40000000) return x*x; /* y is 2 */
+ if(hy==0x3fe00000) { /* y is 0.5 */
+ if(hx>=0) /* x >= +0 */
+ return fd_sqrt(x);
+ }
+ }
+
+ ax = fd_fabs(x);
+ /* special value of x */
+ if(lx==0) {
+ if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+ z = ax; /*x is +-0,+-inf,+-1*/
+ if(hy<0) z = one/z; /* z = (1/|x|) */
+ if(hx<0) {
+ if(((ix-0x3ff00000)|yisint)==0) {
+ z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+ } else if(yisint==1) {
+#ifdef HPUX
+ uz.d = z;
+ __HI(uz) ^= 1<<31; /* some HPUXes cannot negate 0.. */
+ z = uz.d;
+#else
+ z = -z; /* (x<0)**odd = -(|x|**odd) */
+#endif
+ }
+ }
+ return z;
+ }
+ }
+
+ /* (x<0)**(non-int) is NaN */
+ if((((hx>>31)+1)|yisint)==0) return (x-x)/(x-x);
+
+ /* |y| is really_big */
+ if(iy>0x41e00000) { /* if |y| > 2**31 */
+ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
+ if(ix<=0x3fefffff) return (hy<0)? really_big*really_big:tiny*tiny;
+ if(ix>=0x3ff00000) return (hy>0)? really_big*really_big:tiny*tiny;
+ }
+ /* over/underflow if x is not close to one */
+ if(ix<0x3fefffff) return (hy<0)? really_big*really_big:tiny*tiny;
+ if(ix>0x3ff00000) return (hy>0)? really_big*really_big:tiny*tiny;
+ /* now |1-x| is tiny <= 2**-20, suffice to compute
+ log(x) by x-x^2/2+x^3/3-x^4/4 */
+ t = x-1; /* t has 20 trailing zeros */
+ w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+ u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
+ v = t*ivln2_l-w*ivln2;
+ t1 = u+v;
+ uz.d = t1;
+ __LO(uz) = 0;
+ t1 = uz.d;
+ t2 = v-(t1-u);
+ } else {
+ double s_h,t_h;
+ double s2,s_l,t_l;
+ n = 0;
+ /* take care subnormal number */
+ if(ix<0x00100000)
+ {ax *= two53; n -= 53; uz.d = ax; ix = __HI(uz); }
+ n += ((ix)>>20)-0x3ff;
+ j = ix&0x000fffff;
+ /* determine interval */
+ ix = j|0x3ff00000; /* normalize ix */
+ if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
+ else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
+ else {k=0;n+=1;ix -= 0x00100000;}
+ uz.d = ax;
+ __HI(uz) = ix;
+ ax = uz.d;
+
+ /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
+ v = one/(ax+bp[k]);
+ s = u*v;
+ s_h = s;
+ uz.d = s_h;
+ __LO(uz) = 0;
+ s_h = uz.d;
+ /* t_h=ax+bp[k] High */
+ t_h = zero;
+ uz.d = t_h;
+ __HI(uz)=((ix>>1)|0x20000000)+0x00080000+(k<<18);
+ t_h = uz.d;
+ t_l = ax - (t_h-bp[k]);
+ s_l = v*((u-s_h*t_h)-s_h*t_l);
+ /* compute log(ax) */
+ s2 = s*s;
+ r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+ r += s_l*(s_h+s);
+ s2 = s_h*s_h;
+ t_h = 3.0+s2+r;
+ uz.d = t_h;
+ __LO(uz) = 0;
+ t_h = uz.d;
+ t_l = r-((t_h-3.0)-s2);
+ /* u+v = s*(1+...) */
+ u = s_h*t_h;
+ v = s_l*t_h+t_l*s;
+ /* 2/(3log2)*(s+...) */
+ p_h = u+v;
+ uz.d = p_h;
+ __LO(uz) = 0;
+ p_h = uz.d;
+ p_l = v-(p_h-u);
+ z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
+ z_l = cp_l*p_h+p_l*cp+dp_l[k];
+ /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+ t = (double)n;
+ t1 = (((z_h+z_l)+dp_h[k])+t);
+ uz.d = t1;
+ __LO(uz) = 0;
+ t1 = uz.d;
+ t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+ }
+
+ s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+ if((((hx>>31)+1)|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+ y1 = y;
+ uy.d = y1;
+ __LO(uy) = 0;
+ y1 = uy.d;
+ p_l = (y-y1)*t1+y*t2;
+ p_h = y1*t1;
+ z = p_l+p_h;
+ uz.d = z;
+ j = __HI(uz);
+ i = __LO(uz);
+
+ if (j>=0x40900000) { /* z >= 1024 */
+ if(((j-0x40900000)|i)!=0) /* if z > 1024 */
+ return s*really_big*really_big; /* overflow */
+ else {
+ if(p_l+ovt>z-p_h) return s*really_big*really_big; /* overflow */
+ }
+ } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
+ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
+ return s*tiny*tiny; /* underflow */
+ else {
+ if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
+ }
+ }
+ /*
+ * compute 2**(p_h+p_l)
+ */
+ i = j&0x7fffffff;
+ k = (i>>20)-0x3ff;
+ n = 0;
+ if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
+ n = j+(0x00100000>>(k+1));
+ k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
+ t = zero;
+ uz.d = t;
+ __HI(uz) = (n&~(0x000fffff>>k));
+ t = uz.d;
+ n = ((n&0x000fffff)|0x00100000)>>(20-k);
+ if(j<0) n = -n;
+ p_h -= t;
+ }
+ t = p_l+p_h;
+ uz.d = t;
+ __LO(uz) = 0;
+ t = uz.d;
+ u = t*lg2_h;
+ v = (p_l-(t-p_h))*lg2+t*lg2_l;
+ z = u+v;
+ w = v-(z-u);
+ t = z*z;
+ t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ r = (z*t1)/(t1-two)-(w+z*w);
+ z = one-(r-z);
+ uz.d = z;
+ j = __HI(uz);
+ j += (n<<20);
+ if((j>>20)<=0) z = fd_scalbn(z,n); /* subnormal output */
+ else { uz.d = z; __HI(uz) += (n<<20); z = uz.d; }
+ return s*z;
+}
diff --git a/src/dom/js/fdlibm/e_rem_pio2.c b/src/dom/js/fdlibm/e_rem_pio2.c
new file mode 100644
index 000000000..6f9423551
--- /dev/null
+++ b/src/dom/js/fdlibm/e_rem_pio2.c
@@ -0,0 +1,221 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2()
+ */
+
+#include "fdlibm.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+#ifdef __STDC__
+static const int two_over_pi[] = {
+#else
+static int two_over_pi[] = {
+#endif
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
+};
+
+#ifdef __STDC__
+static const int npio2_hw[] = {
+#else
+static int npio2_hw[] = {
+#endif
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2: 53 bits of 2/pi
+ * pio2_1: first 33 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 33 bit of pi/2
+ * pio2_2t: pi/2 - (pio2_1+pio2_2)
+ * pio2_3: third 33 bit of pi/2
+ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+#ifdef __STDC__
+ int __ieee754_rem_pio2(double x, double *y)
+#else
+ int __ieee754_rem_pio2(x,y)
+ double x,y[];
+#endif
+{
+ fd_twoints u, ux, uz;
+ double z,w,t,r,fn;
+ double tx[3];
+ int e0,i,j,nx,n,ix,hx;
+
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ ix = hx&0x7fffffff;
+ if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */
+ {y[0] = x; y[1] = 0; return 0;}
+ if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */
+ if(hx>0) {
+ z = x - pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z - pio2_1t;
+ y[1] = (z-y[0])-pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z -= pio2_2;
+ y[0] = z - pio2_2t;
+ y[1] = (z-y[0])-pio2_2t;
+ }
+ return 1;
+ } else { /* negative x */
+ z = x + pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z + pio2_1t;
+ y[1] = (z-y[0])+pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z += pio2_2;
+ y[0] = z + pio2_2t;
+ y[1] = (z-y[0])+pio2_2t;
+ }
+ return -1;
+ }
+ }
+ if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+ t = fd_fabs(x);
+ n = (int) (t*invpio2+half);
+ fn = (double)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t; /* 1st round good to 85 bit */
+ if(n<32&&ix!=npio2_hw[n-1]) {
+ y[0] = r-w; /* quick check no cancellation */
+ } else {
+ j = ix>>20;
+ y[0] = r-w;
+ u.d = y[0];
+ i = j-(((__HI(u))>>20)&0x7ff);
+ if(i>16) { /* 2nd iteration needed, good to 118 */
+ t = r;
+ w = fn*pio2_2;
+ r = t-w;
+ w = fn*pio2_2t-((t-r)-w);
+ y[0] = r-w;
+ u.d = y[0];
+ i = j-(((__HI(u))>>20)&0x7ff);
+ if(i>49) { /* 3rd iteration need, 151 bits acc */
+ t = r; /* will cover all possible cases */
+ w = fn*pio2_3;
+ r = t-w;
+ w = fn*pio2_3t-((t-r)-w);
+ y[0] = r-w;
+ }
+ }
+ }
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(ix>=0x7ff00000) { /* x is inf or NaN */
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(x)-23) */
+ ux.d = x; uz.d = z;
+ __LO(uz) = __LO(ux);
+ z = uz.d;
+ e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */
+ uz.d = z;
+ __HI(uz) = ix - (e0<<20);
+ z = uz.d;
+ for(i=0;i<2;i++) {
+ tx[i] = (double)((int)(z));
+ z = (z-tx[i])*two24;
+ }
+ tx[2] = z;
+ nx = 3;
+ while(tx[nx-1]==zero) nx--; /* skip zero term */
+ n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
diff --git a/src/dom/js/fdlibm/e_remainder.c b/src/dom/js/fdlibm/e_remainder.c
new file mode 100644
index 000000000..de40f0c2a
--- /dev/null
+++ b/src/dom/js/fdlibm/e_remainder.c
@@ -0,0 +1,120 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_remainder(x,p)
+ * Return :
+ * returns x REM p = x - [x/p]*p as if in infinite
+ * precise arithmetic, where [x/p] is the (infinite bit)
+ * integer nearest x/p (in half way case choose the even one).
+ * Method :
+ * Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double zero = 0.0;
+#else
+static double zero = 0.0;
+#endif
+
+
+#ifdef __STDC__
+ double __ieee754_remainder(double x, double p)
+#else
+ double __ieee754_remainder(x,p)
+ double x,p;
+#endif
+{
+ fd_twoints u;
+ int hx,hp;
+ unsigned sx,lx,lp;
+ double p_half;
+
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ lx = __LO(u); /* low word of x */
+ u.d = p;
+ hp = __HI(u); /* high word of p */
+ lp = __LO(u); /* low word of p */
+ sx = hx&0x80000000;
+ hp &= 0x7fffffff;
+ hx &= 0x7fffffff;
+
+ /* purge off exception values */
+ if((hp|lp)==0) return (x*p)/(x*p); /* p = 0 */
+ if((hx>=0x7ff00000)|| /* x not finite */
+ ((hp>=0x7ff00000)&& /* p is NaN */
+ (((hp-0x7ff00000)|lp)!=0)))
+ return (x*p)/(x*p);
+
+
+ if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p); /* now x < 2p */
+ if (((hx-hp)|(lx-lp))==0) return zero*x;
+ x = fd_fabs(x);
+ p = fd_fabs(p);
+ if (hp<0x00200000) {
+ if(x+x>p) {
+ x-=p;
+ if(x+x>=p) x -= p;
+ }
+ } else {
+ p_half = 0.5*p;
+ if(x>p_half) {
+ x-=p;
+ if(x>=p_half) x -= p;
+ }
+ }
+ u.d = x;
+ __HI(u) ^= sx;
+ x = u.d;
+ return x;
+}
diff --git a/src/dom/js/fdlibm/e_scalb.c b/src/dom/js/fdlibm/e_scalb.c
new file mode 100644
index 000000000..621704ea0
--- /dev/null
+++ b/src/dom/js/fdlibm/e_scalb.c
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_scalb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_scalb(x, fn) is provide for
+ * passing various standard test suite. One
+ * should use scalbn() instead.
+ */
+
+#include "fdlibm.h"
+
+#ifdef _SCALB_INT
+#ifdef __STDC__
+ double __ieee754_scalb(double x, int fn)
+#else
+ double __ieee754_scalb(x,fn)
+ double x; int fn;
+#endif
+#else
+#ifdef __STDC__
+ double __ieee754_scalb(double x, double fn)
+#else
+ double __ieee754_scalb(x,fn)
+ double x, fn;
+#endif
+#endif
+{
+#ifdef _SCALB_INT
+ return fd_scalbn(x,fn);
+#else
+ if (fd_isnan(x)||fd_isnan(fn)) return x*fn;
+ if (!fd_finite(fn)) {
+ if(fn>0.0) return x*fn;
+ else return x/(-fn);
+ }
+ if (fd_rint(fn)!=fn) return (fn-fn)/(fn-fn);
+ if ( fn > 65000.0) return fd_scalbn(x, 65000);
+ if (-fn > 65000.0) return fd_scalbn(x,-65000);
+ return fd_scalbn(x,(int)fn);
+#endif
+}
diff --git a/src/dom/js/fdlibm/e_sinh.c b/src/dom/js/fdlibm/e_sinh.c
new file mode 100644
index 000000000..98ab9b5a3
--- /dev/null
+++ b/src/dom/js/fdlibm/e_sinh.c
@@ -0,0 +1,122 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sinh(x)
+ * Method :
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ * 1. Replace x by |x| (sinh(-x) = -sinh(x)).
+ * 2.
+ * E + E/(E+1)
+ * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x)
+ * 2
+ *
+ * 22 <= x <= lnovft : sinh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : sinh(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ * sinh(x) is |x| if x is +INF, -INF, or NaN.
+ * only sinh(0)=0 is exact for finite x.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double one = 1.0, shuge = 1.0e307;
+#else
+static double one = 1.0, shuge = 1.0e307;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_sinh(double x)
+#else
+ double __ieee754_sinh(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double t,w,h;
+ int ix,jx;
+ unsigned lx;
+
+ /* High word of |x|. */
+ u.d = x;
+ jx = __HI(u);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x+x;
+
+ h = 0.5;
+ if (jx<0) h = -h;
+ /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3e300000) /* |x|<2**-28 */
+ if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+ t = fd_expm1(fd_fabs(x));
+ if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+ return h*(t+t/(t+one));
+ }
+
+ /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+ if (ix < 0x40862E42) return h*__ieee754_exp(fd_fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE || (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+ w = __ieee754_exp(0.5*fd_fabs(x));
+ t = h*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, sinh(x) overflow */
+ return x*shuge;
+}
diff --git a/src/dom/js/fdlibm/e_sqrt.c b/src/dom/js/fdlibm/e_sqrt.c
new file mode 100644
index 000000000..91802839b
--- /dev/null
+++ b/src/dom/js/fdlibm/e_sqrt.c
@@ -0,0 +1,497 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sqrt(x)
+ * Return correctly rounded sqrt.
+ * ------------------------------------------
+ * | Use the hardware sqrt if you have one |
+ * ------------------------------------------
+ * Method:
+ * Bit by bit method using integer arithmetic. (Slow, but portable)
+ * 1. Normalization
+ * Scale x to y in [1,4) with even powers of 2:
+ * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
+ * sqrt(y) = 2^k * sqrt(x)
+ * 2. Bit by bit computation
+ * Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+ * i 0
+ * i+1 2
+ * s = 2*q , and y = 2 * ( y - q ). (1)
+ * i i i i
+ *
+ * To compute q from q , one checks whether
+ * i+1 i
+ *
+ * -(i+1) 2
+ * (q + 2 ) <= y. (2)
+ * i
+ * -(i+1)
+ * If (2) is false, then q = q ; otherwise q = q + 2 .
+ * i+1 i i+1 i
+ *
+ * With some algebric manipulation, it is not difficult to see
+ * that (2) is equivalent to
+ * -(i+1)
+ * s + 2 <= y (3)
+ * i i
+ *
+ * The advantage of (3) is that s and y can be computed by
+ * i i
+ * the following recurrence formula:
+ * if (3) is false
+ *
+ * s = s , y = y ; (4)
+ * i+1 i i+1 i
+ *
+ * otherwise,
+ * -i -(i+1)
+ * s = s + 2 , y = y - s - 2 (5)
+ * i+1 i i+1 i i
+ *
+ * One may easily use induction to prove (4) and (5).
+ * Note. Since the left hand side of (3) contain only i+2 bits,
+ * it does not necessary to do a full (53-bit) comparison
+ * in (3).
+ * 3. Final rounding
+ * After generating the 53 bits result, we compute one more bit.
+ * Together with the remainder, we can decide whether the
+ * result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ * (it will never equal to 1/2ulp).
+ * The rounding mode can be detected by checking whether
+ * huge + tiny is equal to huge, and whether huge - tiny is
+ * equal to huge for some floating point number "huge" and "tiny".
+ *
+ * Special cases:
+ * sqrt(+-0) = +-0 ... exact
+ * sqrt(inf) = inf
+ * sqrt(-ve) = NaN ... with invalid signal
+ * sqrt(NaN) = NaN ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include "fdlibm.h"
+
+#if defined(_MSC_VER)
+/* Microsoft Compiler */
+#pragma warning( disable : 4723 ) /* disables potential divide by 0 warning */
+#endif
+
+#ifdef __STDC__
+static const double one = 1.0, tiny=1.0e-300;
+#else
+static double one = 1.0, tiny=1.0e-300;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_sqrt(double x)
+#else
+ double __ieee754_sqrt(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double z;
+ int sign = (int)0x80000000;
+ unsigned r,t1,s1,ix1,q1;
+ int ix0,s0,q,m,t,i;
+
+ u.d = x;
+ ix0 = __HI(u); /* high word of x */
+ ix1 = __LO(u); /* low word of x */
+
+ /* take care of Inf and NaN */
+ if((ix0&0x7ff00000)==0x7ff00000) {
+ return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+ sqrt(-inf)=sNaN */
+ }
+ /* take care of zero */
+ if(ix0<=0) {
+ if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+ else if(ix0<0)
+ return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
+ }
+ /* normalize x */
+ m = (ix0>>20);
+ if(m==0) { /* subnormal x */
+ while(ix0==0) {
+ m -= 21;
+ ix0 |= (ix1>>11); ix1 <<= 21;
+ }
+ for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+ m -= i-1;
+ ix0 |= (ix1>>(32-i));
+ ix1 <<= i;
+ }
+ m -= 1023; /* unbias exponent */
+ ix0 = (ix0&0x000fffff)|0x00100000;
+ if(m&1){ /* odd m, double x to make it even */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ }
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
+ r = 0x00200000; /* r = moving bit from right to left */
+
+ while(r!=0) {
+ t = s0+r;
+ if(t<=ix0) {
+ s0 = t+r;
+ ix0 -= t;
+ q += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ r = sign;
+ while(r!=0) {
+ t1 = s1+r;
+ t = s0;
+ if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
+ s1 = t1+r;
+ if(((int)(t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+ ix0 -= t;
+ if (ix1 < t1) ix0 -= 1;
+ ix1 -= t1;
+ q1 += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ /* use floating add to find out rounding direction */
+ if((ix0|ix1)!=0) {
+ z = one-tiny; /* trigger inexact flag */
+ if (z>=one) {
+ z = one+tiny;
+ if (q1==(unsigned)0xffffffff) { q1=0; q += 1;}
+ else if (z>one) {
+ if (q1==(unsigned)0xfffffffe) q+=1;
+ q1+=2;
+ } else
+ q1 += (q1&1);
+ }
+ }
+ ix0 = (q>>1)+0x3fe00000;
+ ix1 = q1>>1;
+ if ((q&1)==1) ix1 |= sign;
+ ix0 += (m <<20);
+ u.d = z;
+ __HI(u) = ix0;
+ __LO(u) = ix1;
+ z = u.d;
+ return z;
+}
+
+/*
+Other methods (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan
+and K.C. Ng, written in May, 1986)
+
+ Two algorithms are given here to implement sqrt(x)
+ (IEEE double precision arithmetic) in software.
+ Both supply sqrt(x) correctly rounded. The first algorithm (in
+ Section A) uses newton iterations and involves four divisions.
+ The second one uses reciproot iterations to avoid division, but
+ requires more multiplications. Both algorithms need the ability
+ to chop results of arithmetic operations instead of round them,
+ and the INEXACT flag to indicate when an arithmetic operation
+ is executed exactly with no roundoff error, all part of the
+ standard (IEEE 754-1985). The ability to perform shift, add,
+ subtract and logical AND operations upon 32-bit words is needed
+ too, though not part of the standard.
+
+A. sqrt(x) by Newton Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+
+ 1 11 52 ...widths
+ ------------------------------------------------------
+ x: |s| e | f |
+ ------------------------------------------------------
+ msb lsb msb lsb ...order
+
+
+ ------------------------ ------------------------
+ x0: |s| e | f1 | x1: | f2 |
+ ------------------------ ------------------------
+
+ By performing shifts and subtracts on x0 and x1 (both regarded
+ as integers), we obtain an 8-bit approximation of sqrt(x) as
+ follows.
+
+ k := (x0>>1) + 0x1ff80000;
+ y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits
+ Here k is a 32-bit integer and T1[] is an integer array containing
+ correction terms. Now magically the floating value of y (y's
+ leading 32-bit word is y0, the value of its trailing word is 0)
+ approximates sqrt(x) to almost 8-bit.
+
+ Value of T1:
+ static int T1[32]= {
+ 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592,
+ 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215,
+ 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581,
+ 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,};
+
+ (2) Iterative refinement
+
+ Apply Heron's rule three times to y, we have y approximates
+ sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+ y := (y+x/y)/2 ... almost 17 sig. bits
+ y := (y+x/y)/2 ... almost 35 sig. bits
+ y := y-(y-x/y)/2 ... within 1 ulp
+
+
+ Remark 1.
+ Another way to improve y to within 1 ulp is:
+
+ y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x)
+ y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x)
+
+ 2
+ (x-y )*y
+ y := y + 2* ---------- ...within 1 ulp
+ 2
+ 3y + x
+
+
+ This formula has one division fewer than the one above; however,
+ it requires more multiplications and additions. Also x must be
+ scaled in advance to avoid spurious overflow in evaluating the
+ expression 3y*y+x. Hence it is not recommended uless division
+ is slow. If division is very slow, then one should use the
+ reciproot algorithm given in section B.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ I := FALSE; ... reset INEXACT flag I
+ R := RZ; ... set rounding mode to round-toward-zero
+ z := x/y; ... chopped quotient, possibly inexact
+ If(not I) then { ... if the quotient is exact
+ if(z=y) {
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+ } else {
+ z := z - ulp; ... special rounding
+ }
+ }
+ i := TRUE; ... sqrt(x) is inexact
+ If (r=RN) then z=z+ulp ... rounded-to-nearest
+ If (r=RP) then { ... round-toward-+inf
+ y = y+ulp; z=z+ulp;
+ }
+ y := y+z; ... chopped sum
+ y0:=y0-0x00100000; ... y := y/2 is correctly rounded.
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+
+ (4) Special cases
+
+ Square root of +inf, +-0, or NaN is itself;
+ Square root of a negative number is NaN with invalid signal.
+
+
+B. sqrt(x) by Reciproot Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+ (see section A). By performing shifs and subtracts on x0 and y0,
+ we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+ k := 0x5fe80000 - (x0>>1);
+ y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits
+
+ Here k is a 32-bit integer and T2[] is an integer array
+ containing correction terms. Now magically the floating
+ value of y (y's leading 32-bit word is y0, the value of
+ its trailing word y1 is set to zero) approximates 1/sqrt(x)
+ to almost 7.8-bit.
+
+ Value of T2:
+ static int T2[64]= {
+ 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+ 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+ 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+ 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+ 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+ 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+ 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+ 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+ (2) Iterative refinement
+
+ Apply Reciproot iteration three times to y and multiply the
+ result by x to get an approximation z that matches sqrt(x)
+ to about 1 ulp. To be exact, we will have
+ -1ulp < sqrt(x)-z<1.0625ulp.
+
+ ... set rounding mode to Round-to-nearest
+ y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x)
+ y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+ ... special arrangement for better accuracy
+ z := x*y ... 29 bits to sqrt(x), with z*y<1
+ z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x)
+
+ Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+ (a) the term z*y in the final iteration is always less than 1;
+ (b) the error in the final result is biased upward so that
+ -1 ulp < sqrt(x) - z < 1.0625 ulp
+ instead of |sqrt(x)-z|<1.03125ulp.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ R := RZ; ... set rounding mode to round-toward-zero
+ switch(r) {
+ case RN: ... round-to-nearest
+ if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+ if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+ break;
+ case RZ:case RM: ... round-to-zero or round-to--inf
+ R:=RP; ... reset rounding mod to round-to-+inf
+ if(x<z*z ... rounded up) z = z - ulp; else
+ if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+ break;
+ case RP: ... round-to-+inf
+ if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+ if(x>z*z ...chopped) z = z+ulp;
+ break;
+ }
+
+ Remark 3. The above comparisons can be done in fixed point. For
+ example, to compare x and w=z*z chopped, it suffices to compare
+ x1 and w1 (the trailing parts of x and w), regarding them as
+ two's complement integers.
+
+ ...Is z an exact square root?
+ To determine whether z is an exact square root of x, let z1 be the
+ trailing part of z, and also let x0 and x1 be the leading and
+ trailing parts of x.
+
+ If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+ I := 1; ... Raise Inexact flag: z is not exact
+ else {
+ j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2
+ k := z1 >> 26; ... get z's 25-th and 26-th
+ fraction bits
+ I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+ }
+ R:= r ... restore rounded mode
+ return sqrt(x):=z.
+
+ If multiplication is cheaper then the foregoing red tape, the
+ Inexact flag can be evaluated by
+
+ I := i;
+ I := (z*z!=x) or I.
+
+ Note that z*z can overwrite I; this value must be sensed if it is
+ True.
+
+ Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+ zero.
+
+ --------------------
+ z1: | f2 |
+ --------------------
+ bit 31 bit 0
+
+ Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+ or even of logb(x) have the following relations:
+
+ -------------------------------------------------
+ bit 27,26 of z1 bit 1,0 of x1 logb(x)
+ -------------------------------------------------
+ 00 00 odd and even
+ 01 01 even
+ 10 10 odd
+ 10 00 even
+ 11 01 even
+ -------------------------------------------------
+
+ (4) Special cases (see (4) of Section A).
+
+ */
+
diff --git a/src/dom/js/fdlibm/fdlibm.h b/src/dom/js/fdlibm/fdlibm.h
new file mode 100644
index 000000000..b4063f82f
--- /dev/null
+++ b/src/dom/js/fdlibm/fdlibm.h
@@ -0,0 +1,273 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)fdlibm.h 1.5 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* Modified defines start here.. */
+#undef __LITTLE_ENDIAN
+
+#ifdef _WIN32
+#define huge myhuge
+#define __LITTLE_ENDIAN
+#endif
+
+#ifdef XP_OS2
+#define __LITTLE_ENDIAN
+#endif
+
+#if defined(linux) && defined(__i386__)
+#define __LITTLE_ENDIAN
+#endif
+
+/* End here. The rest is the standard file. */
+
+#ifdef __NEWVALID /* special setup for Sun test regime */
+#if defined(i386) || defined(i486) || \
+ defined(intel) || defined(x86) || defined(i86pc)
+#define __LITTLE_ENDIAN
+#endif
+#endif
+
+typedef union {
+#ifdef __LITTLE_ENDIAN
+ struct { int lo, hi; } ints;
+#else
+ struct { int hi, lo; } ints;
+#endif
+ double d;
+} fd_twoints;
+
+#define __HI(x) x.ints.hi
+#define __LO(x) x.ints.lo
+
+#undef __P
+#ifdef __STDC__
+#define __P(p) p
+#else
+#define __P(p) ()
+#endif
+
+/*
+ * ANSI/POSIX
+ */
+
+extern int signgam;
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+
+enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix};
+
+#define _LIB_VERSION_TYPE enum fdversion
+#define _LIB_VERSION _fdlib_version
+
+/* if global variable _LIB_VERSION is not desirable, one may
+ * change the following to be a constant by:
+ * #define _LIB_VERSION_TYPE const enum version
+ * In that case, after one initializes the value _LIB_VERSION (see
+ * s_lib_version.c) during compile time, it cannot be modified
+ * in the middle of a program
+ */
+extern _LIB_VERSION_TYPE _LIB_VERSION;
+
+#define _IEEE_ fdlibm_ieee
+#define _SVID_ fdlibm_svid
+#define _XOPEN_ fdlibm_xopen
+#define _POSIX_ fdlibm_posix
+
+struct exception {
+ int type;
+ char *name;
+ double arg1;
+ double arg2;
+ double retval;
+};
+
+#define HUGE MAXFLOAT
+
+/*
+ * set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
+ * (one may replace the following line by "#include <values.h>")
+ */
+
+#define X_TLOSS 1.41484755040568800000e+16
+
+#define DOMAIN 1
+#define SING 2
+#define OVERFLOW 3
+#define UNDERFLOW 4
+#define TLOSS 5
+#define PLOSS 6
+
+/*
+ * ANSI/POSIX
+ */
+
+extern double fd_acos __P((double));
+extern double fd_asin __P((double));
+extern double fd_atan __P((double));
+extern double fd_atan2 __P((double, double));
+extern double fd_cos __P((double));
+extern double fd_sin __P((double));
+extern double fd_tan __P((double));
+
+extern double fd_cosh __P((double));
+extern double fd_sinh __P((double));
+extern double fd_tanh __P((double));
+
+extern double fd_exp __P((double));
+extern double fd_frexp __P((double, int *));
+extern double fd_ldexp __P((double, int));
+extern double fd_log __P((double));
+extern double fd_log10 __P((double));
+extern double fd_modf __P((double, double *));
+
+extern double fd_pow __P((double, double));
+extern double fd_sqrt __P((double));
+
+extern double fd_ceil __P((double));
+extern double fd_fabs __P((double));
+extern double fd_floor __P((double));
+extern double fd_fmod __P((double, double));
+
+extern double fd_erf __P((double));
+extern double fd_erfc __P((double));
+extern double fd_gamma __P((double));
+extern double fd_hypot __P((double, double));
+extern int fd_isnan __P((double));
+extern int fd_finite __P((double));
+extern double fd_j0 __P((double));
+extern double fd_j1 __P((double));
+extern double fd_jn __P((int, double));
+extern double fd_lgamma __P((double));
+extern double fd_y0 __P((double));
+extern double fd_y1 __P((double));
+extern double fd_yn __P((int, double));
+
+extern double fd_acosh __P((double));
+extern double fd_asinh __P((double));
+extern double fd_atanh __P((double));
+extern double fd_cbrt __P((double));
+extern double fd_logb __P((double));
+extern double fd_nextafter __P((double, double));
+extern double fd_remainder __P((double, double));
+#ifdef _SCALB_INT
+extern double fd_scalb __P((double, int));
+#else
+extern double fd_scalb __P((double, double));
+#endif
+
+extern int fd_matherr __P((struct exception *));
+
+/*
+ * IEEE Test Vector
+ */
+extern double significand __P((double));
+
+/*
+ * Functions callable from C, intended to support IEEE arithmetic.
+ */
+extern double fd_copysign __P((double, double));
+extern int fd_ilogb __P((double));
+extern double fd_rint __P((double));
+extern double fd_scalbn __P((double, int));
+
+/*
+ * BSD math library entry points
+ */
+extern double fd_expm1 __P((double));
+extern double fd_log1p __P((double));
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+#ifdef _REENTRANT
+extern double gamma_r __P((double, int *));
+extern double lgamma_r __P((double, int *));
+#endif /* _REENTRANT */
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt __P((double));
+extern double __ieee754_acos __P((double));
+extern double __ieee754_acosh __P((double));
+extern double __ieee754_log __P((double));
+extern double __ieee754_atanh __P((double));
+extern double __ieee754_asin __P((double));
+extern double __ieee754_atan2 __P((double,double));
+extern double __ieee754_exp __P((double));
+extern double __ieee754_cosh __P((double));
+extern double __ieee754_fmod __P((double,double));
+extern double __ieee754_pow __P((double,double));
+extern double __ieee754_lgamma_r __P((double,int *));
+extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_lgamma __P((double));
+extern double __ieee754_gamma __P((double));
+extern double __ieee754_log10 __P((double));
+extern double __ieee754_sinh __P((double));
+extern double __ieee754_hypot __P((double,double));
+extern double __ieee754_j0 __P((double));
+extern double __ieee754_j1 __P((double));
+extern double __ieee754_y0 __P((double));
+extern double __ieee754_y1 __P((double));
+extern double __ieee754_jn __P((int,double));
+extern double __ieee754_yn __P((int,double));
+extern double __ieee754_remainder __P((double,double));
+extern int __ieee754_rem_pio2 __P((double,double*));
+#ifdef _SCALB_INT
+extern double __ieee754_scalb __P((double,int));
+#else
+extern double __ieee754_scalb __P((double,double));
+#endif
+
+/* fdlibm kernel function */
+extern double __kernel_standard __P((double,double,int,int*));
+extern double __kernel_sin __P((double,double,int));
+extern double __kernel_cos __P((double,double));
+extern double __kernel_tan __P((double,double,int));
+extern int __kernel_rem_pio2 __P((double*,double*,int,int,int,const int*));
diff --git a/src/dom/js/fdlibm/k_cos.c b/src/dom/js/fdlibm/k_cos.c
new file mode 100644
index 000000000..17b505d58
--- /dev/null
+++ b/src/dom/js/fdlibm/k_cos.c
@@ -0,0 +1,134 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_cos( x, y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ *
+ * Algorithm
+ * 1. Since cos(-x) = cos(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ * 3. cos(x) is approximated by a polynomial of degree 14 on
+ * [0,pi/4]
+ * 4 14
+ * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ * where the remez error is
+ *
+ * | 2 4 6 8 10 12 14 | -58
+ * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
+ * | |
+ *
+ * 4 6 8 10 12 14
+ * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
+ * cos(x) = 1 - x*x/2 + r
+ * since cos(x+y) ~ cos(x) - sin(x)*y
+ * ~ cos(x) - x*y,
+ * a correction term is necessary in cos(x) and hence
+ * cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ * For better accuracy when x > 0.3, let qx = |x|/4 with
+ * the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+ * Then
+ * cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
+ * Note that 1-qx and (x*x/2-qx) is EXACT here, and the
+ * magnitude of the latter is at least a quarter of x*x/2,
+ * thus, reducing the rounding error in the subtraction.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+#ifdef __STDC__
+ double __kernel_cos(double x, double y)
+#else
+ double __kernel_cos(x, y)
+ double x,y;
+#endif
+{
+ fd_twoints u;
+ double a,hz,z,r,qx;
+ int ix;
+ u.d = x;
+ ix = __HI(u)&0x7fffffff; /* ix = |x|'s high word*/
+ if(ix<0x3e400000) { /* if x < 2**27 */
+ if(((int)x)==0) return one; /* generate inexact */
+ }
+ z = x*x;
+ r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+ if(ix < 0x3FD33333) /* if |x| < 0.3 */
+ return one - (0.5*z - (z*r - x*y));
+ else {
+ if(ix > 0x3fe90000) { /* x > 0.78125 */
+ qx = 0.28125;
+ } else {
+ u.d = qx;
+ __HI(u) = ix-0x00200000; /* x/4 */
+ __LO(u) = 0;
+ qx = u.d;
+ }
+ hz = 0.5*z-qx;
+ a = one-qx;
+ return a - (hz - (z*r-x*y));
+ }
+}
diff --git a/src/dom/js/fdlibm/k_rem_pio2.c b/src/dom/js/fdlibm/k_rem_pio2.c
new file mode 100644
index 000000000..d261e190a
--- /dev/null
+++ b/src/dom/js/fdlibm/k_rem_pio2.c
@@ -0,0 +1,354 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ *
+ * __kernel_rem_pio2 return the last three digits of N with
+ * y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ * x[] The input value (must be positive) is broken into nx
+ * pieces of 24-bit integers in double precision format.
+ * x[i] will be the i-th 24 bit of x. The scaled exponent
+ * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
+ * match x's up to 24 bits.
+ *
+ * Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ * e0 = ilogb(z)-23
+ * z = scalbn(z,-e0)
+ * for i = 0,1,2
+ * x[i] = floor(z)
+ * z = (z-x[i])*2**24
+ *
+ *
+ * y[] ouput result in an array of double precision numbers.
+ * The dimension of y[] is:
+ * 24-bit precision 1
+ * 53-bit precision 2
+ * 64-bit precision 2
+ * 113-bit precision 3
+ * The actual value is the sum of them. Thus for 113-bit
+ * precison, one may have to do something like:
+ *
+ * long double t,w,r_head, r_tail;
+ * t = (long double)y[2] + (long double)y[1];
+ * w = (long double)y[0];
+ * r_head = t+w;
+ * r_tail = w - (r_head - t);
+ *
+ * e0 The exponent of x[0]
+ *
+ * nx dimension of x[]
+ *
+ * prec an integer indicating the precision:
+ * 0 24 bits (single)
+ * 1 53 bits (double)
+ * 2 64 bits (extended)
+ * 3 113 bits (quad)
+ *
+ * ipio2[]
+ * integer array, contains the (24*i)-th to (24*i+23)-th
+ * bit of 2/pi after binary point. The corresponding
+ * floating value is
+ *
+ * ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ * double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ * jk jk+1 is the initial number of terms of ipio2[] needed
+ * in the computation. The recommended value is 2,3,4,
+ * 6 for single, double, extended,and quad.
+ *
+ * jz local integer variable indicating the number of
+ * terms of ipio2[] used.
+ *
+ * jx nx - 1
+ *
+ * jv index for pointing to the suitable ipio2[] for the
+ * computation. In general, we want
+ * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ * is an integer. Thus
+ * e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ * Hence jv = max(0,(e0-3)/24).
+ *
+ * jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ * q[] double array with integral value, representing the
+ * 24-bits chunk of the product of x and 2/pi.
+ *
+ * q0 the corresponding exponent of q[0]. Note that the
+ * exponent for q[i] would be q0-24*i.
+ *
+ * PIo2[] double precision array, obtained by cutting pi/2
+ * into 24 bits chunks.
+ *
+ * f[] ipio2[] in floating point
+ *
+ * iq[] integer array by breaking up q[] in 24-bits chunk.
+ *
+ * fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ * ih integer. If >0 it indicates q[] is >= 0.5, hence
+ * it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+#else
+static int init_jk[] = {2,3,4,6};
+#endif
+
+#ifdef __STDC__
+static const double PIo2[] = {
+#else
+static double PIo2[] = {
+#endif
+ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+ 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+ 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+ 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+ 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+zero = 0.0,
+one = 1.0,
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+#ifdef __STDC__
+ int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int *ipio2)
+#else
+ int __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ double x[], y[]; int e0,nx,prec; int ipio2[];
+#endif
+{
+ int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ double z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/24; if(jv<0) jv=0;
+ q0 = e0-24*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (double)((int)(twon24* z));
+ iq[i] = (int)(z-two24*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = fd_scalbn(z,q0); /* actual value of z */
+ z -= 8.0*fd_floor(z*0.125); /* trim off integer >= 8 */
+ n = (int) z;
+ z -= (double)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(24-q0)); n += i;
+ iq[jz-1] -= i<<(24-q0);
+ ih = iq[jz-1]>>(23-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>23;
+ else if(z>=0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x1000000- j;
+ }
+ } else iq[i] = 0xffffff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7fffff; break;
+ case 2:
+ iq[jz-1] &= 0x3fffff; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= fd_scalbn(one,q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (double) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==0.0) {
+ jz -= 1; q0 -= 24;
+ while(iq[jz]==0) { jz--; q0-=24;}
+ } else { /* break z into 24-bit if necessary */
+ z = fd_scalbn(z,-q0);
+ if(z>=two24) {
+ fw = (double)((int)(twon24*z));
+ iq[jz] = (int)(z-two24*fw);
+ jz += 1; q0 += 24;
+ iq[jz] = (int) fw;
+ } else iq[jz] = (int) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = fd_scalbn(one,q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(double)iq[i]; fw*=twon24;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
diff --git a/src/dom/js/fdlibm/k_sin.c b/src/dom/js/fdlibm/k_sin.c
new file mode 100644
index 000000000..d2bdabd6d
--- /dev/null
+++ b/src/dom/js/fdlibm/k_sin.c
@@ -0,0 +1,114 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
+ *
+ * Algorithm
+ * 1. Since sin(-x) = -sin(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.
+ * 3. sin(x) is approximated by a polynomial of degree 13 on
+ * [0,pi/4]
+ * 3 13
+ * sin(x) ~ x + S1*x + ... + S6*x
+ * where
+ *
+ * |sin(x) 2 4 6 8 10 12 | -58
+ * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
+ * | x |
+ *
+ * 4. sin(x+y) = sin(x) + sin'(x')*y
+ * ~ sin(x) + (1-x*x/2)*y
+ * For better accuracy, let
+ * 3 2 2 2 2
+ * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ * then 3 2
+ * sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+#ifdef __STDC__
+ double __kernel_sin(double x, double y, int iy)
+#else
+ double __kernel_sin(x, y, iy)
+ double x,y; int iy; /* iy=0 if y is zero */
+#endif
+{
+ fd_twoints u;
+ double z,r,v;
+ int ix;
+ u.d = x;
+ ix = __HI(u)&0x7fffffff; /* high word of x */
+ if(ix<0x3e400000) /* |x| < 2**-27 */
+ {if((int)x==0) return x;} /* generate inexact */
+ z = x*x;
+ v = z*x;
+ r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
+ if(iy==0) return x+v*(S1+z*r);
+ else return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/src/dom/js/fdlibm/k_standard.c b/src/dom/js/fdlibm/k_standard.c
new file mode 100644
index 000000000..720109c9d
--- /dev/null
+++ b/src/dom/js/fdlibm/k_standard.c
@@ -0,0 +1,785 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)k_standard.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "fdlibm.h"
+
+/* XXX ugly hack to get msvc to link without error. */
+#if _LIB_VERSION == _IEEE_ && !(defined(DARWIN) || defined(XP_MACOSX))
+ int errno;
+# define EDOM 0
+# define ERANGE 0
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef _USE_WRITE
+#include <stdio.h> /* fputs(), stderr */
+#define WRITE2(u,v) fputs(u, stderr)
+#else /* !defined(_USE_WRITE) */
+#include <unistd.h> /* write */
+#define WRITE2(u,v) write(2, u, v)
+#undef fflush
+#endif /* !defined(_USE_WRITE) */
+
+static double zero = 0.0; /* used as const */
+
+/*
+ * Standard conformance (non-IEEE) on exception cases.
+ * Mapping:
+ * 1 -- acos(|x|>1)
+ * 2 -- asin(|x|>1)
+ * 3 -- atan2(+-0,+-0)
+ * 4 -- hypot overflow
+ * 5 -- cosh overflow
+ * 6 -- exp overflow
+ * 7 -- exp underflow
+ * 8 -- y0(0)
+ * 9 -- y0(-ve)
+ * 10-- y1(0)
+ * 11-- y1(-ve)
+ * 12-- yn(0)
+ * 13-- yn(-ve)
+ * 14-- lgamma(finite) overflow
+ * 15-- lgamma(-integer)
+ * 16-- log(0)
+ * 17-- log(x<0)
+ * 18-- log10(0)
+ * 19-- log10(x<0)
+ * 20-- pow(0.0,0.0)
+ * 21-- pow(x,y) overflow
+ * 22-- pow(x,y) underflow
+ * 23-- pow(0,negative)
+ * 24-- pow(neg,non-integral)
+ * 25-- sinh(finite) overflow
+ * 26-- sqrt(negative)
+ * 27-- fmod(x,0)
+ * 28-- remainder(x,0)
+ * 29-- acosh(x<1)
+ * 30-- atanh(|x|>1)
+ * 31-- atanh(|x|=1)
+ * 32-- scalb overflow
+ * 33-- scalb underflow
+ * 34-- j0(|x|>X_TLOSS)
+ * 35-- y0(x>X_TLOSS)
+ * 36-- j1(|x|>X_TLOSS)
+ * 37-- y1(x>X_TLOSS)
+ * 38-- jn(|x|>X_TLOSS, n)
+ * 39-- yn(x>X_TLOSS, n)
+ * 40-- gamma(finite) overflow
+ * 41-- gamma(-integer)
+ * 42-- pow(NaN,0.0)
+ */
+
+
+#ifdef __STDC__
+ double __kernel_standard(double x, double y, int type, int *err)
+#else
+ double __kernel_standard(x,y,type, err)
+ double x,y; int type;int *err;
+#endif
+{
+ struct exception exc;
+#ifndef HUGE_VAL /* this is the only routine that uses HUGE_VAL */
+#define HUGE_VAL inf
+ double inf = 0.0;
+ fd_twoints u;
+
+ u.d = inf;
+ __HI(u) = 0x7ff00000; /* set inf to infinite */
+ inf = u.d;
+#endif
+
+ *err = 0;
+
+#ifdef _USE_WRITE
+ (void) fflush(stdout);
+#endif
+ exc.arg1 = x;
+ exc.arg2 = y;
+ switch(type) {
+ case 1:
+ /* acos(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "acos";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("acos: DOMAIN error\n", 19);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 2:
+ /* asin(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "asin";
+ exc.retval = zero;
+ if(_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("asin: DOMAIN error\n", 19);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 3:
+ /* atan2(+-0,+-0) */
+ exc.arg1 = y;
+ exc.arg2 = x;
+ exc.type = DOMAIN;
+ exc.name = "atan2";
+ exc.retval = zero;
+ if(_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atan2: DOMAIN error\n", 20);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 4:
+ /* hypot(finite,finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "hypot";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 5:
+ /* cosh(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "cosh";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 6:
+ /* exp(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "exp";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 7:
+ /* exp(finite) underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "exp";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 8:
+ /* y0(0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "y0";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y0: DOMAIN error\n", 17);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 9:
+ /* y0(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "y0";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y0: DOMAIN error\n", 17);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 10:
+ /* y1(0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "y1";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y1: DOMAIN error\n", 17);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 11:
+ /* y1(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "y1";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y1: DOMAIN error\n", 17);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 12:
+ /* yn(n,0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "yn";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("yn: DOMAIN error\n", 17);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 13:
+ /* yn(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "yn";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("yn: DOMAIN error\n", 17);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 14:
+ /* lgamma(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "lgamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 15:
+ /* lgamma(-integer) or lgamma(0) */
+ exc.type = SING;
+ exc.name = "lgamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("lgamma: SING error\n", 19);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 16:
+ /* log(0) */
+ exc.type = SING;
+ exc.name = "log";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log: SING error\n", 16);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 17:
+ /* log(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "log";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log: DOMAIN error\n", 18);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 18:
+ /* log10(0) */
+ exc.type = SING;
+ exc.name = "log10";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log10: SING error\n", 18);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 19:
+ /* log10(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "log10";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log10: DOMAIN error\n", 20);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 20:
+ /* pow(0.0,0.0) */
+ /* error only if _LIB_VERSION == _SVID_ */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ exc.retval = zero;
+ if (_LIB_VERSION != _SVID_) exc.retval = 1.0;
+ else if (!fd_matherr(&exc)) {
+ (void) WRITE2("pow(0,0): DOMAIN error\n", 23);
+ *err = EDOM;
+ }
+ break;
+ case 21:
+ /* pow(x,y) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_) {
+ exc.retval = HUGE;
+ y *= 0.5;
+ if(x<zero&&fd_rint(y)!=y) exc.retval = -HUGE;
+ } else {
+ exc.retval = HUGE_VAL;
+ y *= 0.5;
+ if(x<zero&&fd_rint(y)!=y) exc.retval = -HUGE_VAL;
+ }
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 22:
+ /* pow(x,y) underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "pow";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 23:
+ /* 0**neg */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("pow(0,neg): DOMAIN error\n", 25);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 24:
+ /* neg**non-integral */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = zero/zero; /* X/Open allow NaN */
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("neg**non-integral: DOMAIN error\n", 32);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 25:
+ /* sinh(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "sinh";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = ( (x>zero) ? HUGE : -HUGE);
+ else
+ exc.retval = ( (x>zero) ? HUGE_VAL : -HUGE_VAL);
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 26:
+ /* sqrt(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "sqrt";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("sqrt: DOMAIN error\n", 19);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 27:
+ /* fmod(x,0) */
+ exc.type = DOMAIN;
+ exc.name = "fmod";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = x;
+ else
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("fmod: DOMAIN error\n", 20);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 28:
+ /* remainder(x,0) */
+ exc.type = DOMAIN;
+ exc.name = "remainder";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("remainder: DOMAIN error\n", 24);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 29:
+ /* acosh(x<1) */
+ exc.type = DOMAIN;
+ exc.name = "acosh";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("acosh: DOMAIN error\n", 20);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 30:
+ /* atanh(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "atanh";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atanh: DOMAIN error\n", 20);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 31:
+ /* atanh(|x|=1) */
+ exc.type = SING;
+ exc.name = "atanh";
+ exc.retval = x/zero; /* sign(x)*inf */
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atanh: SING error\n", 18);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 32:
+ /* scalb overflow; SVID also returns +-HUGE_VAL */
+ exc.type = OVERFLOW;
+ exc.name = "scalb";
+ exc.retval = x > zero ? HUGE_VAL : -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 33:
+ /* scalb underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "scalb";
+ exc.retval = fd_copysign(zero,x);
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 34:
+ /* j0(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "j0";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ *err = ERANGE;
+ }
+ break;
+ case 35:
+ /* y0(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "y0";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ *err = ERANGE;
+ }
+ break;
+ case 36:
+ /* j1(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "j1";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ *err = ERANGE;
+ }
+ break;
+ case 37:
+ /* y1(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "y1";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ *err = ERANGE;
+ }
+ break;
+ case 38:
+ /* jn(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "jn";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ *err = ERANGE;
+ }
+ break;
+ case 39:
+ /* yn(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "yn";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ *err = ERANGE;
+ }
+ break;
+ case 40:
+ /* gamma(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "gamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = ERANGE;
+ else if (!fd_matherr(&exc)) {
+ *err = ERANGE;
+ }
+ break;
+ case 41:
+ /* gamma(-integer) or gamma(0) */
+ exc.type = SING;
+ exc.name = "gamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ *err = EDOM;
+ else if (!fd_matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("gamma: SING error\n", 18);
+ }
+ *err = EDOM;
+ }
+ break;
+ case 42:
+ /* pow(NaN,0.0) */
+ /* error only if _LIB_VERSION == _SVID_ & _XOPEN_ */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ exc.retval = x;
+ if (_LIB_VERSION == _IEEE_ ||
+ _LIB_VERSION == _POSIX_) exc.retval = 1.0;
+ else if (!fd_matherr(&exc)) {
+ *err = EDOM;
+ }
+ break;
+ }
+ return exc.retval;
+}
diff --git a/src/dom/js/fdlibm/k_tan.c b/src/dom/js/fdlibm/k_tan.c
new file mode 100644
index 000000000..1e7681b88
--- /dev/null
+++ b/src/dom/js/fdlibm/k_tan.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)k_tan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k=1) or
+ * -1/tan (if k= -1) is returned.
+ *
+ * Algorithm
+ * 1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ * 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+ * 3. tan(x) is approximated by a odd polynomial of degree 27 on
+ * [0,0.67434]
+ * 3 27
+ * tan(x) ~ x + T1*x + ... + T13*x
+ * where
+ *
+ * |tan(x) 2 4 26 | -59.2
+ * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
+ * | x |
+ *
+ * Note: tan(x+y) = tan(x) + tan'(x)*y
+ * ~ tan(x) + (1+x*x)*y
+ * Therefore, for better accuracy in computing tan(x+y), let
+ * 3 2 2 2 2
+ * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ * then
+ * 3 2
+ * tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
+ * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include "fdlibm.h"
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pio4 = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+pio4lo= 3.06161699786838301793e-17, /* 0x3C81A626, 0x33145C07 */
+T[] = {
+ 3.33333333333334091986e-01, /* 0x3FD55555, 0x55555563 */
+ 1.33333333333201242699e-01, /* 0x3FC11111, 0x1110FE7A */
+ 5.39682539762260521377e-02, /* 0x3FABA1BA, 0x1BB341FE */
+ 2.18694882948595424599e-02, /* 0x3F9664F4, 0x8406D637 */
+ 8.86323982359930005737e-03, /* 0x3F8226E3, 0xE96E8493 */
+ 3.59207910759131235356e-03, /* 0x3F6D6D22, 0xC9560328 */
+ 1.45620945432529025516e-03, /* 0x3F57DBC8, 0xFEE08315 */
+ 5.88041240820264096874e-04, /* 0x3F4344D8, 0xF2F26501 */
+ 2.46463134818469906812e-04, /* 0x3F3026F7, 0x1A8D1068 */
+ 7.81794442939557092300e-05, /* 0x3F147E88, 0xA03792A6 */
+ 7.14072491382608190305e-05, /* 0x3F12B80F, 0x32F0A7E9 */
+ -1.85586374855275456654e-05, /* 0xBEF375CB, 0xDB605373 */
+ 2.59073051863633712884e-05, /* 0x3EFB2A70, 0x74BF7AD4 */
+};
+
+#ifdef __STDC__
+ double __kernel_tan(double x, double y, int iy)
+#else
+ double __kernel_tan(x, y, iy)
+ double x,y; int iy;
+#endif
+{
+ fd_twoints u;
+ double z,r,v,w,s;
+ int ix,hx;
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ ix = hx&0x7fffffff; /* high word of |x| */
+ if(ix<0x3e300000) /* x < 2**-28 */
+ {if((int)x==0) { /* generate inexact */
+ u.d =x;
+ if(((ix|__LO(u))|(iy+1))==0) return one/fd_fabs(x);
+ else return (iy==1)? x: -one/x;
+ }
+ }
+ if(ix>=0x3FE59428) { /* |x|>=0.6744 */
+ if(hx<0) {x = -x; y = -y;}
+ z = pio4-x;
+ w = pio4lo-y;
+ x = z+w; y = 0.0;
+ }
+ z = x*x;
+ w = z*z;
+ /* Break x^5*(T[1]+x^2*T[2]+...) into
+ * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+ * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+ */
+ r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
+ v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
+ s = z*x;
+ r = y + z*(s*(r+v)+y);
+ r += T[0]*s;
+ w = x+r;
+ if(ix>=0x3FE59428) {
+ v = (double)iy;
+ return (double)(1-((hx>>30)&2))*(v-2.0*(x-(w*w/(w+v)-r)));
+ }
+ if(iy==1) return w;
+ else { /* if allow error up to 2 ulp,
+ simply return -1.0/(x+r) here */
+ /* compute -1.0/(x+r) accurately */
+ double a,t;
+ z = w;
+ u.d = z;
+ __LO(u) = 0;
+ z = u.d;
+ v = r-(z - x); /* z+v = r+x */
+ t = a = -1.0/w; /* a = -1.0/w */
+ u.d = t;
+ __LO(u) = 0;
+ t = u.d;
+ s = 1.0+t*z;
+ return t+a*(s+t*v);
+ }
+}
diff --git a/src/dom/js/fdlibm/s_asinh.c b/src/dom/js/fdlibm/s_asinh.c
new file mode 100644
index 000000000..fdf70a91c
--- /dev/null
+++ b/src/dom/js/fdlibm/s_asinh.c
@@ -0,0 +1,101 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_asinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* asinh(x)
+ * Method :
+ * Based on
+ * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ * we have
+ * asinh(x) := x if 1+x*x=1,
+ * := sign(x)*(log(x)+ln2)) for large |x|, else
+ * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+really_big= 1.00000000000000000000e+300;
+
+#ifdef __STDC__
+ double fd_asinh(double x)
+#else
+ double fd_asinh(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double t,w;
+ int hx,ix;
+ u.d = x;
+ hx = __HI(u);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */
+ if(ix< 0x3e300000) { /* |x|<2**-28 */
+ if(really_big+x>one) return x; /* return x inexact except 0 */
+ }
+ if(ix>0x41b00000) { /* |x| > 2**28 */
+ w = __ieee754_log(fd_fabs(x))+ln2;
+ } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */
+ t = fd_fabs(x);
+ w = __ieee754_log(2.0*t+one/(fd_sqrt(x*x+one)+t));
+ } else { /* 2.0 > |x| > 2**-28 */
+ t = x*x;
+ w =fd_log1p(fd_fabs(x)+t/(one+fd_sqrt(one+t)));
+ }
+ if(hx>0) return w; else return -w;
+}
diff --git a/src/dom/js/fdlibm/s_atan.c b/src/dom/js/fdlibm/s_atan.c
new file mode 100644
index 000000000..99a00c686
--- /dev/null
+++ b/src/dom/js/fdlibm/s_atan.c
@@ -0,0 +1,175 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_atan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atan(x)
+ * Method
+ * 1. Reduce x to positive by atan(x) = -atan(-x).
+ * 2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ * is further reduced to one of the following intervals and the
+ * arctangent of t is evaluated by the corresponding formula:
+ *
+ * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ * [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double atanhi[] = {
+#else
+static double atanhi[] = {
+#endif
+ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+ 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+ 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+#ifdef __STDC__
+static const double atanlo[] = {
+#else
+static double atanlo[] = {
+#endif
+ 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+ 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+ 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+ 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+#ifdef __STDC__
+static const double aT[] = {
+#else
+static double aT[] = {
+#endif
+ 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+ 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+ 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+ 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+ 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+#ifdef __STDC__
+ static const double
+#else
+ static double
+#endif
+one = 1.0,
+really_big = 1.0e300;
+
+#ifdef __STDC__
+ double fd_atan(double x)
+#else
+ double fd_atan(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double w,s1,s2,z;
+ int ix,hx,id;
+
+ u.d = x;
+ hx = __HI(u);
+ ix = hx&0x7fffffff;
+ if(ix>=0x44100000) { /* if |x| >= 2^66 */
+ u.d = x;
+ if(ix>0x7ff00000||
+ (ix==0x7ff00000&&(__LO(u)!=0)))
+ return x+x; /* NaN */
+ if(hx>0) return atanhi[3]+atanlo[3];
+ else return -atanhi[3]-atanlo[3];
+ } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
+ if (ix < 0x3e200000) { /* |x| < 2^-29 */
+ if(really_big+x>one) return x; /* raise inexact */
+ }
+ id = -1;
+ } else {
+ x = fd_fabs(x);
+ if (ix < 0x3ff30000) { /* |x| < 1.1875 */
+ if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */
+ id = 0; x = (2.0*x-one)/(2.0+x);
+ } else { /* 11/16<=|x|< 19/16 */
+ id = 1; x = (x-one)/(x+one);
+ }
+ } else {
+ if (ix < 0x40038000) { /* |x| < 2.4375 */
+ id = 2; x = (x-1.5)/(one+1.5*x);
+ } else { /* 2.4375 <= |x| < 2^66 */
+ id = 3; x = -1.0/x;
+ }
+ }}
+ /* end of argument reduction */
+ z = x*x;
+ w = z*z;
+ /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+ s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+ s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+ if (id<0) return x - x*(s1+s2);
+ else {
+ z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+ return (hx<0)? -z:z;
+ }
+}
diff --git a/src/dom/js/fdlibm/s_cbrt.c b/src/dom/js/fdlibm/s_cbrt.c
new file mode 100644
index 000000000..4aed19b1b
--- /dev/null
+++ b/src/dom/js/fdlibm/s_cbrt.c
@@ -0,0 +1,133 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_cbrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "fdlibm.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+#ifdef __STDC__
+static const unsigned
+#else
+static unsigned
+#endif
+ B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+ B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
+D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
+F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
+G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+#ifdef __STDC__
+ double fd_cbrt(double x)
+#else
+ double fd_cbrt(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ int hx;
+ double r,s,t=0.0,w;
+ unsigned sign;
+
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ sign=hx&0x80000000; /* sign= sign(x) */
+ hx ^=sign;
+ if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+ if((hx|__LO(u))==0) {
+ x = u.d;
+ return(x); /* cbrt(0) is itself */
+ }
+ u.d = x;
+ __HI(u) = hx; /* x <- |x| */
+ x = u.d;
+ /* rough cbrt to 5 bits */
+ if(hx<0x00100000) /* subnormal number */
+ {u.d = t; __HI(u)=0x43500000; t=u.d; /* set t= 2**54 */
+ t*=x; __HI(u)=__HI(u)/3+B2;
+ }
+ else {
+ u.d = t; __HI(u)=hx/3+B1; t = u.d;
+ }
+
+
+ /* new cbrt to 23 bits, may be implemented in single precision */
+ r=t*t/x;
+ s=C+r*t;
+ t*=G+F/(s+E+D/s);
+
+ /* chopped to 20 bits and make it larger than cbrt(x) */
+ u.d = t;
+ __LO(u)=0; __HI(u)+=0x00000001;
+ t = u.d;
+
+ /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+ s=t*t; /* t*t is exact */
+ r=x/s;
+ w=t+t;
+ r=(r-t)/(w+r); /* r-s is exact */
+ t=t+t*r;
+
+ /* retore the sign bit */
+ u.d = t;
+ __HI(u) |= sign;
+ t = u.d;
+ return(t);
+}
diff --git a/src/dom/js/fdlibm/s_ceil.c b/src/dom/js/fdlibm/s_ceil.c
new file mode 100644
index 000000000..826bcac6c
--- /dev/null
+++ b/src/dom/js/fdlibm/s_ceil.c
@@ -0,0 +1,120 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_ceil.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double really_big = 1.0e300;
+#else
+static double really_big = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double fd_ceil(double x)
+#else
+ double fd_ceil(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ int i0,i1,j0;
+ unsigned i,j;
+ u.d = x;
+ i0 = __HI(u);
+ i1 = __LO(u);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(really_big+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0<0) {i0=0x80000000;i1=0;}
+ else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(really_big+x>0.0) { /* raise inexact flag */
+ if(i0>0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(really_big+x>0.0) { /* raise inexact flag */
+ if(i0>0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1 + (1<<(52-j0));
+ if((int)j<i1) i0+=1; /* got a carry */
+ i1 = j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ u.d = x;
+ __HI(u) = i0;
+ __LO(u) = i1;
+ x = u.d;
+ return x;
+}
diff --git a/src/dom/js/fdlibm/s_copysign.c b/src/dom/js/fdlibm/s_copysign.c
new file mode 100644
index 000000000..8869a1233
--- /dev/null
+++ b/src/dom/js/fdlibm/s_copysign.c
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_copysign.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_copysign(double x, double y)
+#else
+ double fd_copysign(x,y)
+ double x,y;
+#endif
+{
+ fd_twoints ux, uy;
+ ux.d = x; uy.d = y;
+ __HI(ux) = (__HI(ux)&0x7fffffff)|(__HI(uy)&0x80000000);
+ x = ux.d;
+ return x;
+}
diff --git a/src/dom/js/fdlibm/s_cos.c b/src/dom/js/fdlibm/s_cos.c
new file mode 100644
index 000000000..3fb0a6b15
--- /dev/null
+++ b/src/dom/js/fdlibm/s_cos.c
@@ -0,0 +1,118 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cosine function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_cos(double x)
+#else
+ double fd_cos(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ u.d = x;
+ ix = __HI(u);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+
+ /* cos(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cos(y[0],y[1]);
+ case 1: return -__kernel_sin(y[0],y[1],1);
+ case 2: return -__kernel_cos(y[0],y[1]);
+ default:
+ return __kernel_sin(y[0],y[1],1);
+ }
+ }
+}
diff --git a/src/dom/js/fdlibm/s_erf.c b/src/dom/js/fdlibm/s_erf.c
new file mode 100644
index 000000000..6eae8de3b
--- /dev/null
+++ b/src/dom/js/fdlibm/s_erf.c
@@ -0,0 +1,356 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_erf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ * x
+ * 2 |\
+ * erf(x) = --------- | exp(-t*t)dt
+ * sqrt(pi) \|
+ * 0
+ *
+ * erfc(x) = 1-erf(x)
+ * Note that
+ * erf(-x) = -erf(x)
+ * erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ * 1. For |x| in [0, 0.84375]
+ * erf(x) = x + x*R(x^2)
+ * erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
+ * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
+ * where R = P/Q where P is an odd poly of degree 8 and
+ * Q is an odd poly of degree 10.
+ * -57.90
+ * | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ * Remark. The formula is derived by noting
+ * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ * and that
+ * 2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ * is close to one. The interval is chosen because the fix
+ * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ * near 0.6174), and by some experiment, 0.84375 is chosen to
+ * guarantee the error is less than one ulp for erf.
+ *
+ * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ * c = 0.84506291151 rounded to single (24 bits)
+ * erf(x) = sign(x) * (c + P1(s)/Q1(s))
+ * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
+ * 1+(c+P1(s)/Q1(s)) if x < 0
+ * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ * Remark: here we use the taylor series expansion at x=1.
+ * erf(1+s) = erf(1) + s*Poly(s)
+ * = 0.845.. + P1(s)/Q1(s)
+ * That is, we use rational approximation to approximate
+ * erf(1+s) - (c = (single)0.84506291151)
+ * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ * where
+ * P1(s) = degree 6 poly in s
+ * Q1(s) = degree 6 poly in s
+ *
+ * 3. For x in [1.25,1/0.35(~2.857143)],
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ * erf(x) = 1 - erfc(x)
+ * where
+ * R1(z) = degree 7 poly in z, (z=1/x^2)
+ * S1(z) = degree 8 poly in z
+ *
+ * 4. For x in [1/0.35,28]
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ * = 2.0 - tiny (if x <= -6)
+ * erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ * erf(x) = sign(x)*(1.0 - tiny)
+ * where
+ * R2(z) = degree 6 poly in z, (z=1/x^2)
+ * S2(z) = degree 7 poly in z
+ *
+ * Note1:
+ * To compute exp(-x*x-0.5625+R/S), let s be a single
+ * precision number and s := x; then
+ * -x*x = -s*s + (s-x)*(s+x)
+ * exp(-x*x-0.5626+R/S) =
+ * exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ * Note2:
+ * Here 4 and 5 make use of the asymptotic series
+ * exp(-x*x)
+ * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ * x*sqrt(pi)
+ * We use rational approximation to approximate
+ * g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ * Here is the error bound for R1/S1 and R2/S2
+ * |R1/S1 - f(x)| < 2**(-62.57)
+ * |R2/S2 - f(x)| < 2**(-61.52)
+ *
+ * 5. For inf > x >= 28
+ * erf(x) = sign(x) *(1 - tiny) (raise inexact)
+ * erfc(x) = tiny*tiny (raise underflow) if x > 0
+ * = 2 - tiny if x<0
+ *
+ * 7. Special case:
+ * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
+ * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ * erfc/erf(NaN) is NaN
+ */
+
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+tiny = 1e-300,
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+ /* c = (float)0.84506291151 */
+erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to erf on [0,0.84375]
+ */
+efx = 1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8= 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to erf in [0.84375,1.25]
+ */
+pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to erfc in [1.25,1/0.35]
+ */
+ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to erfc in [1/.35,28]
+ */
+rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+#ifdef __STDC__
+ double fd_erf(double x)
+#else
+ double fd_erf(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ int hx,ix,i;
+ double R,S,P,Q,s,y,z,r;
+ u.d = x;
+ hx = __HI(u);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erf(nan)=nan */
+ i = ((unsigned)hx>>31)<<1;
+ return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3e300000) { /* |x|<2**-28 */
+ if (ix < 0x00800000)
+ return 0.125*(8.0*x+efx8*x); /*avoid underflow */
+ return x + efx*x;
+ }
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ return x + x*y;
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fd_fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+ }
+ if (ix >= 0x40180000) { /* inf>|x|>=6 */
+ if(hx>=0) return one-tiny; else return tiny-one;
+ }
+ x = fd_fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6E) { /* |x| < 1/0.35 */
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/0.35 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ u.d = z;
+ __LO(u) = 0;
+ z = u.d;
+ r = __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>=0) return one-r/x; else return r/x-one;
+}
+
+#ifdef __STDC__
+ double erfc(double x)
+#else
+ double erfc(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ int hx,ix;
+ double R,S,P,Q,s,y,z,r;
+ u.d = x;
+ hx = __HI(u);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erfc(nan)=nan */
+ /* erfc(+-inf)=0,2 */
+ return (double)(((unsigned)hx>>31)<<1)+one/x;
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3c700000) /* |x|<2**-56 */
+ return one-x;
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ if(hx < 0x3fd00000) { /* x<1/4 */
+ return one-(x+x*y);
+ } else {
+ r = x*y;
+ r += (x-half);
+ return half - r ;
+ }
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fd_fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) {
+ z = one-erx; return z - P/Q;
+ } else {
+ z = erx+P/Q; return one+z;
+ }
+ }
+ if (ix < 0x403c0000) { /* |x|<28 */
+ x = fd_fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6D) { /* |x| < 1/.35 ~ 2.857143*/
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/.35 ~ 2.857143 */
+ if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ u.d = z;
+ __LO(u) = 0;
+ z = u.d;
+ r = __ieee754_exp(-z*z-0.5625)*
+ __ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>0) return r/x; else return two-r/x;
+ } else {
+ if(hx>0) return tiny*tiny; else return two-tiny;
+ }
+}
diff --git a/src/dom/js/fdlibm/s_expm1.c b/src/dom/js/fdlibm/s_expm1.c
new file mode 100644
index 000000000..578d2e144
--- /dev/null
+++ b/src/dom/js/fdlibm/s_expm1.c
@@ -0,0 +1,267 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_expm1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
+ *
+ * Here a correction term c will be computed to compensate
+ * the error in r when rounded to a floating-point number.
+ *
+ * 2. Approximating expm1(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Since
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ * we define R1(r*r) by
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ * That is,
+ * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ * We use a special Reme algorithm on [0,0.347] to generate
+ * a polynomial of degree 5 in r*r to approximate R1. The
+ * maximum error of this polynomial approximation is bounded
+ * by 2**-61. In other words,
+ * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ * where Q1 = -1.6666666666666567384E-2,
+ * Q2 = 3.9682539681370365873E-4,
+ * Q3 = -9.9206344733435987357E-6,
+ * Q4 = 2.5051361420808517002E-7,
+ * Q5 = -6.2843505682382617102E-9;
+ * (where z=r*r, and the values of Q1 to Q5 are listed below)
+ * with error bounded by
+ * | 5 | -61
+ * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
+ * | |
+ *
+ * expm1(r) = exp(r)-1 is then computed by the following
+ * specific way which minimize the accumulation rounding error:
+ * 2 3
+ * r r [ 3 - (R1 + R1*r/2) ]
+ * expm1(r) = r + --- + --- * [--------------------]
+ * 2 2 [ 6 - r*(3 - R1*r/2) ]
+ *
+ * To compensate the error in the argument reduction, we use
+ * expm1(r+c) = expm1(r) + c + expm1(r)*c
+ * ~ expm1(r) + c + r*c
+ * Thus c+r*c will be added in as the correction terms for
+ * expm1(r+c). Now rearrange the term to avoid optimization
+ * screw up:
+ * ( 2 2 )
+ * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
+ * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
+ * ( )
+ *
+ * = r - E
+ * 3. Scale back to obtain expm1(x):
+ * From step 1, we have
+ * expm1(x) = either 2^k*[expm1(r)+1] - 1
+ * = or 2^k*[expm1(r) + (1-2^-k)]
+ * 4. Implementation notes:
+ * (A). To save one multiplication, we scale the coefficient Qi
+ * to Qi*2^i, and replace z by (x^2)/2.
+ * (B). To achieve maximum accuracy, we compute expm1(x) by
+ * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ * (ii) if k=0, return r-E
+ * (iii) if k=-1, return 0.5*(r-E)-0.5
+ * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ * else return 1.0+2.0*(r-E);
+ * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ * (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ * expm1(INF) is INF, expm1(NaN) is NaN;
+ * expm1(-INF) is -1, and
+ * for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+really_big = 1.0e+300,
+tiny = 1.0e-300,
+o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+ /* scaled coefficients related to expm1 */
+Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+#ifdef __STDC__
+ double fd_expm1(double x)
+#else
+ double fd_expm1(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double y,hi,lo,c,t,e,hxs,hfx,r1;
+ int k,xsb;
+ unsigned hx;
+
+ u.d = x;
+ hx = __HI(u); /* high word of x */
+ xsb = hx&0x80000000; /* sign bit of x */
+ if(xsb==0) y=x; else y= -x; /* y = |x| */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out huge and non-finite argument */
+ if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ u.d = x;
+ if(((hx&0xfffff)|__LO(u))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+ }
+ if(x > o_threshold) return really_big*really_big; /* overflow */
+ }
+ if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+ if(x+tiny<0.0) /* raise inexact */
+ return tiny-one; /* return -1 */
+ }
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ if(xsb==0)
+ {hi = x - ln2_hi; lo = ln2_lo; k = 1;}
+ else
+ {hi = x + ln2_hi; lo = -ln2_lo; k = -1;}
+ } else {
+ k = (int)(invln2*x+((xsb==0)?0.5:-0.5));
+ t = k;
+ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
+ lo = t*ln2_lo;
+ }
+ x = hi - lo;
+ c = (hi-x)-lo;
+ }
+ else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */
+ t = really_big+x; /* return x with inexact flags when x!=0 */
+ return x - (t-(really_big+x));
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ hfx = 0.5*x;
+ hxs = x*hfx;
+ r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+ t = 3.0-r1*hfx;
+ e = hxs*((r1-t)/(6.0 - x*t));
+ if(k==0) return x - (x*e-hxs); /* c is 0 */
+ else {
+ e = (x*(e-c)-c);
+ e -= hxs;
+ if(k== -1) return 0.5*(x-e)-0.5;
+ if(k==1)
+ if(x < -0.25) return -2.0*(e-(x+0.5));
+ else return one+2.0*(x-e);
+ if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */
+ y = one-(e-x);
+ u.d = y;
+ __HI(u) += (k<<20); /* add k to y's exponent */
+ y = u.d;
+ return y-one;
+ }
+ t = one;
+ if(k<20) {
+ u.d = t;
+ __HI(u) = 0x3ff00000 - (0x200000>>k); /* t=1-2^-k */
+ t = u.d;
+ y = t-(e-x);
+ u.d = y;
+ __HI(u) += (k<<20); /* add k to y's exponent */
+ y = u.d;
+ } else {
+ u.d = t;
+ __HI(u) = ((0x3ff-k)<<20); /* 2^-k */
+ t = u.d;
+ y = x-(e+t);
+ y += one;
+ u.d = y;
+ __HI(u) += (k<<20); /* add k to y's exponent */
+ y = u.d;
+ }
+ }
+ return y;
+}
diff --git a/src/dom/js/fdlibm/s_fabs.c b/src/dom/js/fdlibm/s_fabs.c
new file mode 100644
index 000000000..6b029da10
--- /dev/null
+++ b/src/dom/js/fdlibm/s_fabs.c
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_fabs.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_fabs(double x)
+#else
+ double fd_fabs(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ u.d = x;
+ __HI(u) &= 0x7fffffff;
+ x = u.d;
+ return x;
+}
diff --git a/src/dom/js/fdlibm/s_finite.c b/src/dom/js/fdlibm/s_finite.c
new file mode 100644
index 000000000..4a0a4d3c6
--- /dev/null
+++ b/src/dom/js/fdlibm/s_finite.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_finite.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * finite(x) returns 1 is x is finite, else 0;
+ * no branching!
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ int fd_finite(double x)
+#else
+ int fd_finite(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ int hx;
+ u.d = x;
+ hx = __HI(u);
+ return (unsigned)((hx&0x7fffffff)-0x7ff00000)>>31;
+}
diff --git a/src/dom/js/fdlibm/s_floor.c b/src/dom/js/fdlibm/s_floor.c
new file mode 100644
index 000000000..6c23495f0
--- /dev/null
+++ b/src/dom/js/fdlibm/s_floor.c
@@ -0,0 +1,121 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_floor.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floor(x).
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double really_big = 1.0e300;
+#else
+static double really_big = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double fd_floor(double x)
+#else
+ double fd_floor(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ int i0,i1,j0;
+ unsigned i,j;
+ u.d = x;
+ i0 = __HI(u);
+ i1 = __LO(u);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(really_big+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0>=0) {i0=i1=0;}
+ else if(((i0&0x7fffffff)|i1)!=0)
+ { i0=0xbff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(really_big+x>0.0) { /* raise inexact flag */
+ if(i0<0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(really_big+x>0.0) { /* raise inexact flag */
+ if(i0<0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1+(1<<(52-j0));
+ if((int)j<i1) i0 +=1 ; /* got a carry */
+ i1=j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ u.d = x;
+ __HI(u) = i0;
+ __LO(u) = i1;
+ x = u.d;
+ return x;
+}
diff --git a/src/dom/js/fdlibm/s_frexp.c b/src/dom/js/fdlibm/s_frexp.c
new file mode 100644
index 000000000..bec2ecebc
--- /dev/null
+++ b/src/dom/js/fdlibm/s_frexp.c
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_frexp.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * for non-zero x
+ * x = frexp(arg,&exp);
+ * return a double fp quantity x such that 0.5 <= |x| <1.0
+ * and the corresponding binary exponent "exp". That is
+ * arg = x*2^exp.
+ * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg
+ * with *exp=0.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
+
+#ifdef __STDC__
+ double fd_frexp(double x, int *eptr)
+#else
+ double fd_frexp(x, eptr)
+ double x; int *eptr;
+#endif
+{
+ int hx, ix, lx;
+ fd_twoints u;
+ u.d = x;
+ hx = __HI(u);
+ ix = 0x7fffffff&hx;
+ lx = __LO(u);
+ *eptr = 0;
+ if(ix>=0x7ff00000||((ix|lx)==0)) return x; /* 0,inf,nan */
+ if (ix<0x00100000) { /* subnormal */
+ x *= two54;
+ u.d = x;
+ hx = __HI(u);
+ ix = hx&0x7fffffff;
+ *eptr = -54;
+ }
+ *eptr += (ix>>20)-1022;
+ hx = (hx&0x800fffff)|0x3fe00000;
+ u.d = x;
+ __HI(u) = hx;
+ x = u.d;
+ return x;
+}
diff --git a/src/dom/js/fdlibm/s_ilogb.c b/src/dom/js/fdlibm/s_ilogb.c
new file mode 100644
index 000000000..f769781a6
--- /dev/null
+++ b/src/dom/js/fdlibm/s_ilogb.c
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_ilogb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = 0x80000001
+ * ilogb(inf/NaN) = 0x7fffffff (no signal is raised)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ int fd_ilogb(double x)
+#else
+ int fd_ilogb(x)
+ double x;
+#endif
+{
+ int hx,lx,ix;
+ fd_twoints u;
+ u.d = x;
+ hx = (__HI(u))&0x7fffffff; /* high word of x */
+ if(hx<0x00100000) {
+ lx = __LO(u);
+ if((hx|lx)==0)
+ return 0x80000001; /* ilogb(0) = 0x80000001 */
+ else /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043; lx>0; lx<<=1) ix -=1;
+ } else {
+ for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+ }
+ return ix;
+ }
+ else if (hx<0x7ff00000) return (hx>>20)-1023;
+ else return 0x7fffffff;
+}
diff --git a/src/dom/js/fdlibm/s_isnan.c b/src/dom/js/fdlibm/s_isnan.c
new file mode 100644
index 000000000..52f8759c7
--- /dev/null
+++ b/src/dom/js/fdlibm/s_isnan.c
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_isnan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * isnan(x) returns 1 is x is nan, else 0;
+ * no branching!
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ int fd_isnan(double x)
+#else
+ int fd_isnan(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ int hx,lx;
+ u.d = x;
+ hx = (__HI(u)&0x7fffffff);
+ lx = __LO(u);
+ hx |= (unsigned)(lx|(-lx))>>31;
+ hx = 0x7ff00000 - hx;
+ return ((unsigned)(hx))>>31;
+}
diff --git a/src/dom/js/fdlibm/s_ldexp.c b/src/dom/js/fdlibm/s_ldexp.c
new file mode 100644
index 000000000..9475520d4
--- /dev/null
+++ b/src/dom/js/fdlibm/s_ldexp.c
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_ldexp.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+#include <errno.h>
+
+#ifdef __STDC__
+ double fd_ldexp(double value, int exp)
+#else
+ double fd_ldexp(value, exp)
+ double value; int exp;
+#endif
+{
+ if(!fd_finite(value)||value==0.0) return value;
+ value = fd_scalbn(value,exp);
+ if(!fd_finite(value)||value==0.0) errno = ERANGE;
+ return value;
+}
diff --git a/src/dom/js/fdlibm/s_lib_version.c b/src/dom/js/fdlibm/s_lib_version.c
new file mode 100644
index 000000000..2ccf67d51
--- /dev/null
+++ b/src/dom/js/fdlibm/s_lib_version.c
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_lib_version.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * MACRO for standards
+ */
+
+#include "fdlibm.h"
+
+/*
+ * define and initialize _LIB_VERSION
+ */
+#ifdef _POSIX_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _POSIX_;
+#else
+#ifdef _XOPEN_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _XOPEN_;
+#else
+#ifdef _SVID3_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _SVID_;
+#else /* default _IEEE_MODE */
+_LIB_VERSION_TYPE _LIB_VERSION = _IEEE_;
+#endif
+#endif
+#endif
diff --git a/src/dom/js/fdlibm/s_log1p.c b/src/dom/js/fdlibm/s_log1p.c
new file mode 100644
index 000000000..1840156b1
--- /dev/null
+++ b/src/dom/js/fdlibm/s_log1p.c
@@ -0,0 +1,211 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_log1p.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double log1p(double x)
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * 1+x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * Note. If k=0, then f=x is exact. However, if k!=0, then f
+ * may not be representable exactly. In that case, a correction
+ * term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ * and add back the correction term c/u.
+ * (Note: when x > 2**53, one can simply return log(x))
+ *
+ * 2. Approximation of log1p(f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
+ * (the values of Lp1 to Lp7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lp1*s +...+Lp7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ * 3. Finally, log1p(x) = k*ln2 + log1p(f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ * log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ * log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ * algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ * u = 1+x;
+ * if(u==1.0) return x ; else
+ * return log(u)*(x/(u-1.0));
+ *
+ * See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double fd_log1p(double x)
+#else
+ double fd_log1p(x)
+ double x;
+#endif
+{
+ double hfsq,f,c,s,z,R,u;
+ int k,hx,hu,ax;
+ fd_twoints un;
+
+ un.d = x;
+ hx = __HI(un); /* high word of x */
+ ax = hx&0x7fffffff;
+
+ k = 1;
+ if (hx < 0x3FDA827A) { /* x < 0.41422 */
+ if(ax>=0x3ff00000) { /* x <= -1.0 */
+ if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+ else return (x-x)/(x-x); /* log1p(x<-1)=NaN */
+ }
+ if(ax<0x3e200000) { /* |x| < 2**-29 */
+ if(two54+x>zero /* raise inexact */
+ &&ax<0x3c900000) /* |x| < 2**-54 */
+ return x;
+ else
+ return x - x*x*0.5;
+ }
+ if(hx>0||hx<=((int)0xbfd2bec3)) {
+ k=0;f=x;hu=1;} /* -0.2929<x<0.41422 */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ if(k!=0) {
+ if(hx<0x43400000) {
+ u = 1.0+x;
+ un.d = u;
+ hu = __HI(un); /* high word of u */
+ k = (hu>>20)-1023;
+ c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+ c /= u;
+ } else {
+ u = x;
+ un.d = u;
+ hu = __HI(un); /* high word of u */
+ k = (hu>>20)-1023;
+ c = 0;
+ }
+ hu &= 0x000fffff;
+ if(hu<0x6a09e) {
+ un.d = u;
+ __HI(un) = hu|0x3ff00000; /* normalize u */
+ u = un.d;
+ } else {
+ k += 1;
+ un.d = u;
+ __HI(un) = hu|0x3fe00000; /* normalize u/2 */
+ u = un.d;
+ hu = (0x00100000-hu)>>2;
+ }
+ f = u-1.0;
+ }
+ hfsq=0.5*f*f;
+ if(hu==0) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero;
+ else {c += k*ln2_lo; return k*ln2_hi+c;}
+ R = hfsq*(1.0-0.66666666666666666*f);
+ if(k==0) return f-R; else
+ return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+ }
+ s = f/(2.0+f);
+ z = s*s;
+ R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/src/dom/js/fdlibm/s_logb.c b/src/dom/js/fdlibm/s_logb.c
new file mode 100644
index 000000000..f885c4dc3
--- /dev/null
+++ b/src/dom/js/fdlibm/s_logb.c
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_logb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * double logb(x)
+ * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
+ * Use ilogb instead.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_logb(double x)
+#else
+ double fd_logb(x)
+ double x;
+#endif
+{
+ int lx,ix;
+ fd_twoints u;
+
+ u.d = x;
+ ix = (__HI(u))&0x7fffffff; /* high |x| */
+ lx = __LO(u); /* low x */
+ if((ix|lx)==0) return -1.0/fd_fabs(x);
+ if(ix>=0x7ff00000) return x*x;
+ if((ix>>=20)==0) /* IEEE 754 logb */
+ return -1022.0;
+ else
+ return (double) (ix-1023);
+}
diff --git a/src/dom/js/fdlibm/s_matherr.c b/src/dom/js/fdlibm/s_matherr.c
new file mode 100644
index 000000000..cd99ca88f
--- /dev/null
+++ b/src/dom/js/fdlibm/s_matherr.c
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_matherr.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ int fd_matherr(struct exception *x)
+#else
+ int fd_matherr(x)
+ struct exception *x;
+#endif
+{
+ int n=0;
+ if(x->arg1!=x->arg1) return 0;
+ return n;
+}
diff --git a/src/dom/js/fdlibm/s_modf.c b/src/dom/js/fdlibm/s_modf.c
new file mode 100644
index 000000000..3b182bd3b
--- /dev/null
+++ b/src/dom/js/fdlibm/s_modf.c
@@ -0,0 +1,132 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_modf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ * Bit twiddling.
+ *
+ * Exception:
+ * No exception.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double one = 1.0;
+#else
+static double one = 1.0;
+#endif
+
+#ifdef __STDC__
+ double fd_modf(double x, double *iptr)
+#else
+ double fd_modf(x, iptr)
+ double x,*iptr;
+#endif
+{
+ int i0,i1,j0;
+ unsigned i;
+ fd_twoints u;
+ u.d = x;
+ i0 = __HI(u); /* high x */
+ i1 = __LO(u); /* low x */
+ j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */
+ if(j0<20) { /* integer part in high x */
+ if(j0<0) { /* |x|<1 */
+ u.d = *iptr;
+ __HI(u) = i0&0x80000000;
+ __LO(u) = 0; /* *iptr = +-0 */
+ *iptr = u.d;
+ return x;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) { /* x is integral */
+ *iptr = x;
+ u.d = x;
+ __HI(u) &= 0x80000000;
+ __LO(u) = 0; /* return +-0 */
+ x = u.d;
+ return x;
+ } else {
+ u.d = *iptr;
+ __HI(u) = i0&(~i);
+ __LO(u) = 0;
+ *iptr = u.d;
+ return x - *iptr;
+ }
+ }
+ } else if (j0>51) { /* no fraction part */
+ *iptr = x*one;
+ u.d = x;
+ __HI(u) &= 0x80000000;
+ __LO(u) = 0; /* return +-0 */
+ x = u.d;
+ return x;
+ } else { /* fraction part in low x */
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) { /* x is integral */
+ *iptr = x;
+ u.d = x;
+ __HI(u) &= 0x80000000;
+ __LO(u) = 0; /* return +-0 */
+ x = u.d;
+ return x;
+ } else {
+ u.d = *iptr;
+ __HI(u) = i0;
+ __LO(u) = i1&(~i);
+ *iptr = u.d;
+ return x - *iptr;
+ }
+ }
+}
diff --git a/src/dom/js/fdlibm/s_nextafter.c b/src/dom/js/fdlibm/s_nextafter.c
new file mode 100644
index 000000000..f71c5c835
--- /dev/null
+++ b/src/dom/js/fdlibm/s_nextafter.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_nextafter.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ * nextafter(x,y)
+ * return the next machine floating-point number of x in the
+ * direction toward y.
+ * Special cases:
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_nextafter(double x, double y)
+#else
+ double fd_nextafter(x,y)
+ double x,y;
+#endif
+{
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+ fd_twoints ux, uy;
+
+ ux.d = x; uy.d = y;
+ hx = __HI(ux); /* high word of x */
+ lx = __LO(ux); /* low word of x */
+ hy = __HI(uy); /* high word of y */
+ ly = __LO(uy); /* low word of y */
+ ix = hx&0x7fffffff; /* |x| */
+ iy = hy&0x7fffffff; /* |y| */
+
+ if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */
+ ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */
+ return x+y;
+ if(x==y) return x; /* x=y, return x */
+ if((ix|lx)==0) { /* x == 0 */
+ ux.d = x;
+ __HI(ux) = hy&0x80000000; /* return +-minsubnormal */
+ __LO(ux) = 1;
+ x = ux.d;
+ y = x*x;
+ if(y==x) return y; else return x; /* raise underflow flag */
+ }
+ if(hx>=0) { /* x > 0 */
+ if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x < y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ } else { /* x < 0 */
+ if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x > y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ }
+ hy = hx&0x7ff00000;
+ if(hy>=0x7ff00000) return x+x; /* overflow */
+ if(hy<0x00100000) { /* underflow */
+ y = x*x;
+ if(y!=x) { /* raise underflow flag */
+ uy.d = y;
+ __HI(uy) = hx; __LO(uy) = lx;
+ y = uy.d;
+ return y;
+ }
+ }
+ ux.d = x;
+ __HI(ux) = hx; __LO(ux) = lx;
+ x = ux.d;
+ return x;
+}
diff --git a/src/dom/js/fdlibm/s_rint.c b/src/dom/js/fdlibm/s_rint.c
new file mode 100644
index 000000000..3c4fab6d9
--- /dev/null
+++ b/src/dom/js/fdlibm/s_rint.c
@@ -0,0 +1,131 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_rint.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ * Using floating addition.
+ * Exception:
+ * Inexact flag raised if x not equal to rint(x).
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+TWO52[2]={
+ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+#ifdef __STDC__
+ double fd_rint(double x)
+#else
+ double fd_rint(x)
+ double x;
+#endif
+{
+ int i0,j0,sx;
+ unsigned i,i1;
+ double w,t;
+ fd_twoints u;
+
+ u.d = x;
+ i0 = __HI(u);
+ sx = (i0>>31)&1;
+ i1 = __LO(u);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) {
+ if(((i0&0x7fffffff)|i1)==0) return x;
+ i1 |= (i0&0x0fffff);
+ i0 &= 0xfffe0000;
+ i0 |= ((i1|-(int)i1)>>12)&0x80000;
+ u.d = x;
+ __HI(u)=i0;
+ x = u.d;
+ w = TWO52[sx]+x;
+ t = w-TWO52[sx];
+ u.d = t;
+ i0 = __HI(u);
+ __HI(u) = (i0&0x7fffffff)|(sx<<31);
+ t = u.d;
+ return t;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ i>>=1;
+ if(((i0&i)|i1)!=0) {
+ if(j0==19) i1 = 0x40000000; else
+ i0 = (i0&(~i))|((0x20000)>>j0);
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ i>>=1;
+ if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+ }
+ u.d = x;
+ __HI(u) = i0;
+ __LO(u) = i1;
+ x = u.d;
+ w = TWO52[sx]+x;
+ return w-TWO52[sx];
+}
diff --git a/src/dom/js/fdlibm/s_scalbn.c b/src/dom/js/fdlibm/s_scalbn.c
new file mode 100644
index 000000000..3deeaa305
--- /dev/null
+++ b/src/dom/js/fdlibm/s_scalbn.c
@@ -0,0 +1,107 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_scalbn.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n computed by exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+really_big = 1.0e+300,
+tiny = 1.0e-300;
+
+#ifdef __STDC__
+ double fd_scalbn (double x, int n)
+#else
+ double fd_scalbn (x,n)
+ double x; int n;
+#endif
+{
+ fd_twoints u;
+ int k,hx,lx;
+ u.d = x;
+ hx = __HI(u);
+ lx = __LO(u);
+ k = (hx&0x7ff00000)>>20; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+ x *= two54;
+ u.d = x;
+ hx = __HI(u);
+ k = ((hx&0x7ff00000)>>20) - 54;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0x7ff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k > 0x7fe) return really_big*fd_copysign(really_big,x); /* overflow */
+ if (k > 0) /* normal result */
+ {u.d = x; __HI(u) = (hx&0x800fffff)|(k<<20); x = u.d; return x;}
+ if (k <= -54) {
+ if (n > 50000) /* in case integer overflow in n+k */
+ return really_big*fd_copysign(really_big,x); /*overflow*/
+ else return tiny*fd_copysign(tiny,x); /*underflow*/
+ }
+ k += 54; /* subnormal result */
+ u.d = x;
+ __HI(u) = (hx&0x800fffff)|(k<<20);
+ x = u.d;
+ return x*twom54;
+}
diff --git a/src/dom/js/fdlibm/s_signgam.c b/src/dom/js/fdlibm/s_signgam.c
new file mode 100644
index 000000000..4eb8ce72f
--- /dev/null
+++ b/src/dom/js/fdlibm/s_signgam.c
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#include "fdlibm.h"
+int signgam = 0;
diff --git a/src/dom/js/fdlibm/s_significand.c b/src/dom/js/fdlibm/s_significand.c
new file mode 100644
index 000000000..2e1c0b28f
--- /dev/null
+++ b/src/dom/js/fdlibm/s_significand.c
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_significand.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * significand(x) computes just
+ * scalb(x, (double) -ilogb(x)),
+ * for exercising the fraction-part(F) IEEE 754-1985 test vector.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_significand(double x)
+#else
+ double fd_significand(x)
+ double x;
+#endif
+{
+ return __ieee754_scalb(x,(double) -fd_ilogb(x));
+}
diff --git a/src/dom/js/fdlibm/s_sin.c b/src/dom/js/fdlibm/s_sin.c
new file mode 100644
index 000000000..8bbc5c62d
--- /dev/null
+++ b/src/dom/js/fdlibm/s_sin.c
@@ -0,0 +1,118 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cose function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_sin(double x)
+#else
+ double fd_sin(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ u.d = x;
+ ix = __HI(u);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
+
+ /* sin(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sin(y[0],y[1],1);
+ case 1: return __kernel_cos(y[0],y[1]);
+ case 2: return -__kernel_sin(y[0],y[1],1);
+ default:
+ return -__kernel_cos(y[0],y[1]);
+ }
+ }
+}
diff --git a/src/dom/js/fdlibm/s_tan.c b/src/dom/js/fdlibm/s_tan.c
new file mode 100644
index 000000000..ded36c1d7
--- /dev/null
+++ b/src/dom/js/fdlibm/s_tan.c
@@ -0,0 +1,112 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_tan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ * __kernel_tan ... tangent function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_tan(double x)
+#else
+ double fd_tan(x)
+ double x;
+#endif
+{
+ fd_twoints u;
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ u.d = x;
+ ix = __HI(u);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);
+
+ /* tan(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x; /* NaN */
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
+ -1 -- n odd */
+ }
+}
diff --git a/src/dom/js/fdlibm/s_tanh.c b/src/dom/js/fdlibm/s_tanh.c
new file mode 100644
index 000000000..aa6809f85
--- /dev/null
+++ b/src/dom/js/fdlibm/s_tanh.c
@@ -0,0 +1,122 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)s_tanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ * x -x
+ * e - e
+ * 0. tanh(x) is defined to be -----------
+ * x -x
+ * e + e
+ * 1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ * 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+x)
+ * -t
+ * 2**-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x)
+ * t + 2
+ * 2
+ * 1 <= x <= 22.0 : tanh(x) := 1- ----- ; t=expm1(2x)
+ * t + 2
+ * 22.0 < x <= INF : tanh(x) := 1.
+ *
+ * Special cases:
+ * tanh(NaN) is NaN;
+ * only tanh(0)=0 is exact for finite argument.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+#else
+static double one=1.0, two=2.0, tiny = 1.0e-300;
+#endif
+
+#ifdef __STDC__
+ double fd_tanh(double x)
+#else
+ double fd_tanh(x)
+ double x;
+#endif
+{
+ double t,z;
+ int jx,ix;
+ fd_twoints u;
+
+ /* High word of |x|. */
+ u.d = x;
+ jx = __HI(u);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) {
+ if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
+ else return one/x-one; /* tanh(NaN) = NaN */
+ }
+
+ /* |x| < 22 */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3c800000) /* |x|<2**-55 */
+ return x*(one+x); /* tanh(small) = small */
+ if (ix>=0x3ff00000) { /* |x|>=1 */
+ t = fd_expm1(two*fd_fabs(x));
+ z = one - two/(t+two);
+ } else {
+ t = fd_expm1(-two*fd_fabs(x));
+ z= -t/(t+two);
+ }
+ /* |x| > 22, return +-1 */
+ } else {
+ z = one - tiny; /* raised inexact flag */
+ }
+ return (jx>=0)? z: -z;
+}
diff --git a/src/dom/js/fdlibm/w_acos.c b/src/dom/js/fdlibm/w_acos.c
new file mode 100644
index 000000000..872c81d20
--- /dev/null
+++ b/src/dom/js/fdlibm/w_acos.c
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrap_acos(x)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_acos(double x) /* wrapper acos */
+#else
+ double fd_acos(x) /* wrapper acos */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_acos(x);
+#else
+ double z;
+ z = __ieee754_acos(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ if(fd_fabs(x)>1.0) {
+ int err;
+ return __kernel_standard(x,x,1,&err); /* acos(|x|>1) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_acosh.c b/src/dom/js/fdlibm/w_acosh.c
new file mode 100644
index 000000000..745d402ea
--- /dev/null
+++ b/src/dom/js/fdlibm/w_acosh.c
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/*
+ * wrapper acosh(x)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_acosh(double x) /* wrapper acosh */
+#else
+ double fd_acosh(x) /* wrapper acosh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_acosh(x);
+#else
+ double z;
+ z = __ieee754_acosh(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ if(x<1.0) {
+ int err;
+ return __kernel_standard(x,x,29,&err); /* acosh(x<1) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_asin.c b/src/dom/js/fdlibm/w_asin.c
new file mode 100644
index 000000000..18aaefde9
--- /dev/null
+++ b/src/dom/js/fdlibm/w_asin.c
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/*
+ * wrapper asin(x)
+ */
+
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_asin(double x) /* wrapper asin */
+#else
+ double fd_asin(x) /* wrapper asin */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_asin(x);
+#else
+ double z;
+ z = __ieee754_asin(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ if(fd_fabs(x)>1.0) {
+ int err;
+ return __kernel_standard(x,x,2,&err); /* asin(|x|>1) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_atan2.c b/src/dom/js/fdlibm/w_atan2.c
new file mode 100644
index 000000000..8cfa4bbbd
--- /dev/null
+++ b/src/dom/js/fdlibm/w_atan2.c
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/*
+ * wrapper atan2(y,x)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_atan2(double y, double x) /* wrapper atan2 */
+#else
+ double fd_atan2(y,x) /* wrapper atan2 */
+ double y,x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_atan2(y,x);
+#else
+ double z;
+ z = __ieee754_atan2(y,x);
+ if(_LIB_VERSION == _IEEE_||fd_isnan(x)||fd_isnan(y)) return z;
+ if(x==0.0&&y==0.0) {
+ int err;
+ return __kernel_standard(y,x,3,&err); /* atan2(+-0,+-0) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_atanh.c b/src/dom/js/fdlibm/w_atanh.c
new file mode 100644
index 000000000..6ba52d1e2
--- /dev/null
+++ b/src/dom/js/fdlibm/w_atanh.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+/*
+ * wrapper atanh(x)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_atanh(double x) /* wrapper atanh */
+#else
+ double fd_atanh(x) /* wrapper atanh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_atanh(x);
+#else
+ double z,y;
+ z = __ieee754_atanh(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ y = fd_fabs(x);
+ if(y>=1.0) {
+ int err;
+ if(y>1.0)
+ return __kernel_standard(x,x,30,&err); /* atanh(|x|>1) */
+ else
+ return __kernel_standard(x,x,31,&err); /* atanh(|x|==1) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_cosh.c b/src/dom/js/fdlibm/w_cosh.c
new file mode 100644
index 000000000..146449e02
--- /dev/null
+++ b/src/dom/js/fdlibm/w_cosh.c
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper cosh(x)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_cosh(double x) /* wrapper cosh */
+#else
+ double fd_cosh(x) /* wrapper cosh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_cosh(x);
+#else
+ double z;
+ z = __ieee754_cosh(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ if(fd_fabs(x)>7.10475860073943863426e+02) {
+ int err;
+ return __kernel_standard(x,x,5,&err); /* cosh overflow */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_exp.c b/src/dom/js/fdlibm/w_exp.c
new file mode 100644
index 000000000..f5dea0b01
--- /dev/null
+++ b/src/dom/js/fdlibm/w_exp.c
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_exp.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper exp(x)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02; /* 0xc0874910, 0xD52D3051 */
+
+#ifdef __STDC__
+ double fd_exp(double x) /* wrapper exp */
+#else
+ double fd_exp(x) /* wrapper exp */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_exp(x);
+#else
+ double z;
+ z = __ieee754_exp(x);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(fd_finite(x)) {
+ int err;
+ if(x>o_threshold)
+ return __kernel_standard(x,x,6,&err); /* exp overflow */
+ else if(x<u_threshold)
+ return __kernel_standard(x,x,7,&err); /* exp underflow */
+ }
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_fmod.c b/src/dom/js/fdlibm/w_fmod.c
new file mode 100644
index 000000000..76862096d
--- /dev/null
+++ b/src/dom/js/fdlibm/w_fmod.c
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper fmod(x,y)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_fmod(double x, double y) /* wrapper fmod */
+#else
+ double fd_fmod(x,y) /* wrapper fmod */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_fmod(x,y);
+#else
+ double z;
+ z = __ieee754_fmod(x,y);
+ if(_LIB_VERSION == _IEEE_ ||fd_isnan(y)||fd_isnan(x)) return z;
+ if(y==0.0) {
+ int err;
+ return __kernel_standard(x,y,27,&err); /* fmod(x,0) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_gamma.c b/src/dom/js/fdlibm/w_gamma.c
new file mode 100644
index 000000000..9eb8e429c
--- /dev/null
+++ b/src/dom/js/fdlibm/w_gamma.c
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_gamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* double gamma(double x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call gamma_r
+ */
+
+#include "fdlibm.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double fd_gamma(double x)
+#else
+ double fd_gamma(x)
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_gamma_r(x,&signgam);
+#else
+ double y;
+ y = __ieee754_gamma_r(x,&signgam);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!fd_finite(y)&&fd_finite(x)) {
+ int err;
+ if(fd_floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,41,&err); /* gamma pole */
+ else
+ return __kernel_standard(x,x,40,&err); /* gamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_gamma_r.c b/src/dom/js/fdlibm/w_gamma_r.c
new file mode 100644
index 000000000..2669b4f59
--- /dev/null
+++ b/src/dom/js/fdlibm/w_gamma_r.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_gamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper double gamma_r(double x, int *signgamp)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_gamma_r(double x, int *signgamp) /* wrapper lgamma_r */
+#else
+ double fd_gamma_r(x,signgamp) /* wrapper lgamma_r */
+ double x; int *signgamp;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_gamma_r(x,signgamp);
+#else
+ double y;
+ y = __ieee754_gamma_r(x,signgamp);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!fd_finite(y)&&fd_finite(x)) {
+ int err;
+ if(fd_floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,41,&err); /* gamma pole */
+ else
+ return __kernel_standard(x,x,40,&err); /* gamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_hypot.c b/src/dom/js/fdlibm/w_hypot.c
new file mode 100644
index 000000000..bfaac66c0
--- /dev/null
+++ b/src/dom/js/fdlibm/w_hypot.c
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper hypot(x,y)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_hypot(double x, double y)/* wrapper hypot */
+#else
+ double fd_hypot(x,y) /* wrapper hypot */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_hypot(x,y);
+#else
+ double z;
+ z = __ieee754_hypot(x,y);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if((!fd_finite(z))&&fd_finite(x)&&fd_finite(y)) {
+ int err;
+ return __kernel_standard(x,y,4,&err); /* hypot overflow */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_j0.c b/src/dom/js/fdlibm/w_j0.c
new file mode 100644
index 000000000..5e676ff60
--- /dev/null
+++ b/src/dom/js/fdlibm/w_j0.c
@@ -0,0 +1,105 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper j0(double x), y0(double x)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_j0(double x) /* wrapper j0 */
+#else
+ double fd_j0(x) /* wrapper j0 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_j0(x);
+#else
+ double z = __ieee754_j0(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ if(fd_fabs(x)>X_TLOSS) {
+ int err;
+ return __kernel_standard(x,x,34,&err); /* j0(|x|>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double y0(double x) /* wrapper y0 */
+#else
+ double y0(x) /* wrapper y0 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_y0(x);
+#else
+ double z;
+ int err;
+ z = __ieee754_y0(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard(x,x,8,&err);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard(x,x,9,&err);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard(x,x,35,&err); /* y0(x>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_j1.c b/src/dom/js/fdlibm/w_j1.c
new file mode 100644
index 000000000..86a506bc2
--- /dev/null
+++ b/src/dom/js/fdlibm/w_j1.c
@@ -0,0 +1,106 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper of j1,y1
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_j1(double x) /* wrapper j1 */
+#else
+ double fd_j1(x) /* wrapper j1 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_j1(x);
+#else
+ double z;
+ z = __ieee754_j1(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x) ) return z;
+ if(fd_fabs(x)>X_TLOSS) {
+ int err;
+ return __kernel_standard(x,x,36,&err); /* j1(|x|>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double y1(double x) /* wrapper y1 */
+#else
+ double y1(x) /* wrapper y1 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_y1(x);
+#else
+ double z;
+ int err;
+ z = __ieee754_y1(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard(x,x,10,&err);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard(x,x,11,&err);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard(x,x,37,&err); /* y1(x>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_jn.c b/src/dom/js/fdlibm/w_jn.c
new file mode 100644
index 000000000..6926b0da8
--- /dev/null
+++ b/src/dom/js/fdlibm/w_jn.c
@@ -0,0 +1,128 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_jn.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper jn(int n, double x), yn(int n, double x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_jn(int n, double x) /* wrapper jn */
+#else
+ double fd_jn(n,x) /* wrapper jn */
+ double x; int n;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_jn(n,x);
+#else
+ double z;
+ z = __ieee754_jn(n,x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x) ) return z;
+ if(fd_fabs(x)>X_TLOSS) {
+ int err;
+ return __kernel_standard((double)n,x,38,&err); /* jn(|x|>X_TLOSS,n) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double yn(int n, double x) /* wrapper yn */
+#else
+ double yn(n,x) /* wrapper yn */
+ double x; int n;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_yn(n,x);
+#else
+ double z;
+ int err;
+ z = __ieee754_yn(n,x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard((double)n,x,12,&err);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard((double)n,x,13,&err);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard((double)n,x,39,&err); /* yn(x>X_TLOSS,n) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_lgamma.c b/src/dom/js/fdlibm/w_lgamma.c
new file mode 100644
index 000000000..f7576e892
--- /dev/null
+++ b/src/dom/js/fdlibm/w_lgamma.c
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_lgamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* double lgamma(double x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include "fdlibm.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double fd_lgamma(double x)
+#else
+ double fd_lgamma(x)
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_lgamma_r(x,&signgam);
+#else
+ double y;
+ y = __ieee754_lgamma_r(x,&signgam);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!fd_finite(y)&&fd_finite(x)) {
+ int err;
+ if(fd_floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,15,&err); /* lgamma pole */
+ else
+ return __kernel_standard(x,x,14,&err); /* lgamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_lgamma_r.c b/src/dom/js/fdlibm/w_lgamma_r.c
new file mode 100644
index 000000000..ba2ad5933
--- /dev/null
+++ b/src/dom/js/fdlibm/w_lgamma_r.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper double lgamma_r(double x, int *signgamp)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_lgamma_r(double x, int *signgamp) /* wrapper lgamma_r */
+#else
+ double fd_lgamma_r(x,signgamp) /* wrapper lgamma_r */
+ double x; int *signgamp;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_lgamma_r(x,signgamp);
+#else
+ double y;
+ y = __ieee754_lgamma_r(x,signgamp);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!fd_finite(y)&&fd_finite(x)) {
+ int err;
+ if(fd_floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,15,&err); /* lgamma pole */
+ else
+ return __kernel_standard(x,x,14,&err); /* lgamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_log.c b/src/dom/js/fdlibm/w_log.c
new file mode 100644
index 000000000..7e358fcf1
--- /dev/null
+++ b/src/dom/js/fdlibm/w_log.c
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper log(x)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_log(double x) /* wrapper log */
+#else
+ double fd_log(x) /* wrapper log */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_log(x);
+#else
+ double z;
+ int err;
+ z = __ieee754_log(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x) || x > 0.0) return z;
+ if(x==0.0)
+ return __kernel_standard(x,x,16,&err); /* log(0) */
+ else
+ return __kernel_standard(x,x,17,&err); /* log(x<0) */
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_log10.c b/src/dom/js/fdlibm/w_log10.c
new file mode 100644
index 000000000..6b298b236
--- /dev/null
+++ b/src/dom/js/fdlibm/w_log10.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper log10(X)
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_log10(double x) /* wrapper log10 */
+#else
+ double fd_log10(x) /* wrapper log10 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_log10(x);
+#else
+ double z;
+ z = __ieee754_log10(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ if(x<=0.0) {
+ int err;
+ if(x==0.0)
+ return __kernel_standard(x,x,18,&err); /* log10(0) */
+ else
+ return __kernel_standard(x,x,19,&err); /* log10(x<0) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_pow.c b/src/dom/js/fdlibm/w_pow.c
new file mode 100644
index 000000000..3d2c15ad3
--- /dev/null
+++ b/src/dom/js/fdlibm/w_pow.c
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/* @(#)w_pow.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper pow(x,y) return x**y
+ */
+
+#include "fdlibm.h"
+
+
+#ifdef __STDC__
+ double fd_pow(double x, double y) /* wrapper pow */
+#else
+ double fd_pow(x,y) /* wrapper pow */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_pow(x,y);
+#else
+ double z;
+ int err;
+ z=__ieee754_pow(x,y);
+ if(_LIB_VERSION == _IEEE_|| fd_isnan(y)) return z;
+ if(fd_isnan(x)) {
+ if(y==0.0)
+ return __kernel_standard(x,y,42,&err); /* pow(NaN,0.0) */
+ else
+ return z;
+ }
+ if(x==0.0){
+ if(y==0.0)
+ return __kernel_standard(x,y,20,&err); /* pow(0.0,0.0) */
+ if(fd_finite(y)&&y<0.0)
+ return __kernel_standard(x,y,23,&err); /* pow(0.0,negative) */
+ return z;
+ }
+ if(!fd_finite(z)) {
+ if(fd_finite(x)&&fd_finite(y)) {
+ if(fd_isnan(z))
+ return __kernel_standard(x,y,24,&err); /* pow neg**non-int */
+ else
+ return __kernel_standard(x,y,21,&err); /* pow overflow */
+ }
+ }
+ if(z==0.0&&fd_finite(x)&&fd_finite(y))
+ return __kernel_standard(x,y,22,&err); /* pow underflow */
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_remainder.c b/src/dom/js/fdlibm/w_remainder.c
new file mode 100644
index 000000000..25d1ba171
--- /dev/null
+++ b/src/dom/js/fdlibm/w_remainder.c
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper remainder(x,p)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_remainder(double x, double y) /* wrapper remainder */
+#else
+ double fd_remainder(x,y) /* wrapper remainder */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_remainder(x,y);
+#else
+ double z;
+ z = __ieee754_remainder(x,y);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(y)) return z;
+ if(y==0.0) {
+ int err;
+ return __kernel_standard(x,y,28,&err); /* remainder(x,0) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_scalb.c b/src/dom/js/fdlibm/w_scalb.c
new file mode 100644
index 000000000..35c16a500
--- /dev/null
+++ b/src/dom/js/fdlibm/w_scalb.c
@@ -0,0 +1,95 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_scalb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper scalb(double x, double fn) is provide for
+ * passing various standard test suite. One
+ * should use scalbn() instead.
+ */
+
+#include "fdlibm.h"
+
+#include <errno.h>
+
+#ifdef __STDC__
+#ifdef _SCALB_INT
+ double fd_scalb(double x, int fn) /* wrapper scalb */
+#else
+ double fd_scalb(double x, double fn) /* wrapper scalb */
+#endif
+#else
+ double fd_scalb(x,fn) /* wrapper scalb */
+#ifdef _SCALB_INT
+ double x; int fn;
+#else
+ double x,fn;
+#endif
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_scalb(x,fn);
+#else
+ double z;
+ int err;
+ z = __ieee754_scalb(x,fn);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(!(fd_finite(z)||fd_isnan(z))&&fd_finite(x)) {
+ return __kernel_standard(x,(double)fn,32,&err); /* scalb overflow */
+ }
+ if(z==0.0&&z!=x) {
+ return __kernel_standard(x,(double)fn,33,&err); /* scalb underflow */
+ }
+#ifndef _SCALB_INT
+ if(!fd_finite(fn)) errno = ERANGE;
+#endif
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_sinh.c b/src/dom/js/fdlibm/w_sinh.c
new file mode 100644
index 000000000..8b04ecb7f
--- /dev/null
+++ b/src/dom/js/fdlibm/w_sinh.c
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper sinh(x)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_sinh(double x) /* wrapper sinh */
+#else
+ double fd_sinh(x) /* wrapper sinh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_sinh(x);
+#else
+ double z;
+ z = __ieee754_sinh(x);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(!fd_finite(z)&&fd_finite(x)) {
+ int err;
+ return __kernel_standard(x,x,25,&err); /* sinh overflow */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/fdlibm/w_sqrt.c b/src/dom/js/fdlibm/w_sqrt.c
new file mode 100644
index 000000000..462d776f8
--- /dev/null
+++ b/src/dom/js/fdlibm/w_sqrt.c
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* @(#)w_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper sqrt(x)
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ double fd_sqrt(double x) /* wrapper sqrt */
+#else
+ double fd_sqrt(x) /* wrapper sqrt */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_sqrt(x);
+#else
+ double z;
+ z = __ieee754_sqrt(x);
+ if(_LIB_VERSION == _IEEE_ || fd_isnan(x)) return z;
+ if(x<0.0) {
+ int err;
+ return __kernel_standard(x,x,26,&err); /* sqrt(negative) */
+ } else
+ return z;
+#endif
+}
diff --git a/src/dom/js/js.c b/src/dom/js/js.c
new file mode 100644
index 000000000..5bd296223
--- /dev/null
+++ b/src/dom/js/js.c
@@ -0,0 +1,2333 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS shell.
+ */
+#include "jsstddef.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h"
+#include "jsutil.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsdbgapi.h"
+#include "jsemit.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jslock.h"
+#include "jsobj.h"
+#include "jsparse.h"
+#include "jsscope.h"
+#include "jsscript.h"
+
+#ifdef PERLCONNECT
+#include "perlconnect/jsperl.h"
+#endif
+
+#ifdef LIVECONNECT
+#include "jsjava.h"
+#endif
+
+#ifdef JSDEBUGGER
+#include "jsdebug.h"
+#ifdef JSDEBUGGER_JAVA_UI
+#include "jsdjava.h"
+#endif /* JSDEBUGGER_JAVA_UI */
+#ifdef JSDEBUGGER_C_UI
+#include "jsdb.h"
+#endif /* JSDEBUGGER_C_UI */
+#endif /* JSDEBUGGER */
+
+#ifdef XP_UNIX
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif
+
+#if defined(XP_WIN) || defined(XP_OS2)
+#include <io.h> /* for isatty() */
+#endif
+
+#define EXITCODE_RUNTIME_ERROR 3
+#define EXITCODE_FILE_NOT_FOUND 4
+
+size_t gStackChunkSize = 8192;
+static size_t gMaxStackSize = 0;
+static jsuword gStackBase;
+int gExitCode = 0;
+JSBool gQuitting = JS_FALSE;
+FILE *gErrFile = NULL;
+FILE *gOutFile = NULL;
+
+#ifdef XP_MAC
+#if defined(MAC_TEST_HACK) || defined(XP_MAC_MPW)
+/* this is the data file that all Print strings will be echoed into */
+FILE *gTestResultFile = NULL;
+#define isatty(f) 0
+#else
+#define isatty(f) 1
+#endif
+
+char *strdup(const char *str)
+{
+ char *copy = (char *) malloc(strlen(str)+1);
+ if (copy)
+ strcpy(copy, str);
+ return copy;
+}
+
+#ifdef XP_MAC_MPW
+/* Macintosh MPW replacements for the ANSI routines. These translate LF's to CR's because
+ the MPW libraries supplied by Metrowerks don't do that for some reason. */
+static void translateLFtoCR(char *str, int length)
+{
+ char *limit = str + length;
+ while (str != limit) {
+ if (*str == '\n')
+ *str = '\r';
+ str++;
+ }
+}
+
+int fputc(int c, FILE *file)
+{
+ char buffer = c;
+ if (buffer == '\n')
+ buffer = '\r';
+ return fwrite(&buffer, 1, 1, file);
+}
+
+int fputs(const char *s, FILE *file)
+{
+ char buffer[4096];
+ int n = strlen(s);
+ int extra = 0;
+
+ while (n > sizeof buffer) {
+ memcpy(buffer, s, sizeof buffer);
+ translateLFtoCR(buffer, sizeof buffer);
+ extra += fwrite(buffer, 1, sizeof buffer, file);
+ n -= sizeof buffer;
+ s += sizeof buffer;
+ }
+ memcpy(buffer, s, n);
+ translateLFtoCR(buffer, n);
+ return extra + fwrite(buffer, 1, n, file);
+}
+
+int fprintf(FILE* file, const char *format, ...)
+{
+ va_list args;
+ char smallBuffer[4096];
+ int n;
+ int bufferSize = sizeof smallBuffer;
+ char *buffer = smallBuffer;
+ int result;
+
+ va_start(args, format);
+ n = vsnprintf(buffer, bufferSize, format, args);
+ va_end(args);
+ while (n < 0) {
+ if (buffer != smallBuffer)
+ free(buffer);
+ bufferSize <<= 1;
+ buffer = malloc(bufferSize);
+ if (!buffer) {
+ JS_ASSERT(JS_FALSE);
+ return 0;
+ }
+ va_start(args, format);
+ n = vsnprintf(buffer, bufferSize, format, args);
+ va_end(args);
+ }
+ translateLFtoCR(buffer, n);
+ result = fwrite(buffer, 1, n, file);
+ if (buffer != smallBuffer)
+ free(buffer);
+ return result;
+}
+
+
+#else
+#include <SIOUX.h>
+#include <MacTypes.h>
+
+static char* mac_argv[] = { "js", NULL };
+
+static void initConsole(StringPtr consoleName, const char* startupMessage, int *argc, char** *argv)
+{
+ SIOUXSettings.autocloseonquit = true;
+ SIOUXSettings.asktosaveonclose = false;
+ /* SIOUXSettings.initializeTB = false;
+ SIOUXSettings.showstatusline = true;*/
+ puts(startupMessage);
+ SIOUXSetTitle(consoleName);
+
+ /* set up a buffer for stderr (otherwise it's a pig). */
+ setvbuf(stderr, (char *) malloc(BUFSIZ), _IOLBF, BUFSIZ);
+
+ *argc = 1;
+ *argv = mac_argv;
+}
+
+#ifdef LIVECONNECT
+/* Little hack to provide a default CLASSPATH on the Mac. */
+#define getenv(var) mac_getenv(var)
+static char* mac_getenv(const char* var)
+{
+ if (strcmp(var, "CLASSPATH") == 0) {
+ static char class_path[] = "liveconnect.jar";
+ return class_path;
+ }
+ return NULL;
+}
+#endif /* LIVECONNECT */
+
+#endif
+#endif
+
+#ifdef JSDEBUGGER
+static JSDContext *_jsdc;
+#ifdef JSDEBUGGER_JAVA_UI
+static JSDJContext *_jsdjc;
+#endif /* JSDEBUGGER_JAVA_UI */
+#endif /* JSDEBUGGER */
+
+static JSBool reportWarnings = JS_TRUE;
+
+typedef enum JSShellErrNum {
+#define MSG_DEF(name, number, count, exception, format) \
+ name = number,
+#include "jsshell.msg"
+#undef MSG_DEF
+ JSShellErr_Limit
+#undef MSGDEF
+} JSShellErrNum;
+
+static const JSErrorFormatString *
+my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber);
+
+#ifdef EDITLINE
+extern char *readline(const char *prompt);
+extern void add_history(char *line);
+#endif
+
+static JSBool
+GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
+#ifdef EDITLINE
+ /*
+ * Use readline only if file is stdin, because there's no way to specify
+ * another handle. Are other filehandles interactive?
+ */
+ if (file == stdin) {
+ char *linep = readline(prompt);
+ if (!linep)
+ return JS_FALSE;
+ if (linep[0] != '\0')
+ add_history(linep);
+ strcpy(bufp, linep);
+ JS_free(cx, linep);
+ bufp += strlen(bufp);
+ *bufp++ = '\n';
+ *bufp = '\0';
+ } else
+#endif
+ {
+ char line[256];
+ fprintf(gOutFile, prompt);
+ fflush(gOutFile);
+#ifdef XP_MAC_MPW
+ /* Print a CR after the prompt because MPW grabs the entire line when entering an interactive command */
+ fputc('\n', gOutFile);
+#endif
+ if (!fgets(line, sizeof line, file))
+ return JS_FALSE;
+ strcpy(bufp, line);
+ }
+ return JS_TRUE;
+}
+
+static void
+Process(JSContext *cx, JSObject *obj, char *filename)
+{
+ JSBool ok, hitEOF;
+ JSScript *script;
+ jsval result;
+ JSString *str;
+ char buffer[4096];
+ char *bufp;
+ int lineno;
+ int startline;
+ FILE *file;
+ jsuword stackLimit;
+
+ if (!filename || strcmp(filename, "-") == 0) {
+ file = stdin;
+ } else {
+ file = fopen(filename, "r");
+ if (!file) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
+ JSSMSG_CANT_OPEN, filename, strerror(errno));
+ gExitCode = EXITCODE_FILE_NOT_FOUND;
+ return;
+ }
+ }
+
+ if (gMaxStackSize == 0) {
+ /*
+ * Disable checking for stack overflow if limit is zero.
+ */
+ stackLimit = 0;
+ } else {
+#if JS_STACK_GROWTH_DIRECTION > 0
+ stackLimit = gStackBase + gMaxStackSize;
+#else
+ stackLimit = gStackBase - gMaxStackSize;
+#endif
+ }
+ JS_SetThreadStackLimit(cx, stackLimit);
+
+ if (!isatty(fileno(file))) {
+ /*
+ * It's not interactive - just execute it.
+ *
+ * Support the UNIX #! shell hack; gobble the first line if it starts
+ * with '#'. TODO - this isn't quite compatible with sharp variables,
+ * as a legal js program (using sharp variables) might start with '#'.
+ * But that would require multi-character lookahead.
+ */
+ int ch = fgetc(file);
+ if (ch == '#') {
+ while((ch = fgetc(file)) != EOF) {
+ if (ch == '\n' || ch == '\r')
+ break;
+ }
+ }
+ ungetc(ch, file);
+ script = JS_CompileFileHandle(cx, obj, filename, file);
+ if (script) {
+ (void)JS_ExecuteScript(cx, obj, script, &result);
+ JS_DestroyScript(cx, script);
+ }
+ return;
+ }
+
+ /* It's an interactive filehandle; drop into read-eval-print loop. */
+ lineno = 1;
+ hitEOF = JS_FALSE;
+ do {
+ bufp = buffer;
+ *bufp = '\0';
+
+ /*
+ * Accumulate lines until we get a 'compilable unit' - one that either
+ * generates an error (before running out of source) or that compiles
+ * cleanly. This should be whenever we get a complete statement that
+ * coincides with the end of a line.
+ */
+ startline = lineno;
+ do {
+ if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
+ hitEOF = JS_TRUE;
+ break;
+ }
+ bufp += strlen(bufp);
+ lineno++;
+ } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
+
+ /* Clear any pending exception from previous failed compiles. */
+ JS_ClearPendingException(cx);
+ script = JS_CompileScript(cx, obj, buffer, strlen(buffer),
+#ifdef JSDEBUGGER
+ "typein",
+#else
+ NULL,
+#endif
+ startline);
+ if (script) {
+ ok = JS_ExecuteScript(cx, obj, script, &result);
+ if (ok && result != JSVAL_VOID) {
+ str = JS_ValueToString(cx, result);
+ if (str)
+ fprintf(gOutFile, "%s\n", JS_GetStringBytes(str));
+ else
+ ok = JS_FALSE;
+ }
+ JS_DestroyScript(cx, script);
+ }
+ } while (!hitEOF && !gQuitting);
+ fprintf(gOutFile, "\n");
+ return;
+}
+
+static int
+usage(void)
+{
+ fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
+ fprintf(gErrFile, "usage: js [-PswW] [-b branchlimit] [-c stackchunksize] [-v version] [-f scriptfile] [-S maxstacksize] [scriptfile] [scriptarg...]\n");
+ return 2;
+}
+
+static uint32 gBranchCount;
+static uint32 gBranchLimit;
+
+static JSBool
+my_BranchCallback(JSContext *cx, JSScript *script)
+{
+ if (++gBranchCount == gBranchLimit) {
+ if (script->filename)
+ fprintf(gErrFile, "%s:", script->filename);
+ fprintf(gErrFile, "%u: script branches too much (%u callbacks)\n",
+ script->lineno, gBranchLimit);
+ gBranchCount = 0;
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+extern JSClass global_class;
+
+static int
+ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
+{
+ int i, j, length;
+ JSObject *argsObj;
+ char *filename = NULL;
+ JSBool isInteractive = JS_TRUE;
+
+ /*
+ * Scan past all optional arguments so we can create the arguments object
+ * before processing any -f options, which must interleave properly with
+ * -v and -w options. This requires two passes, and without getopt, we'll
+ * have to keep the option logic here and in the second for loop in sync.
+ */
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] != '-' || argv[i][1] == '\0') {
+ ++i;
+ break;
+ }
+ switch (argv[i][1]) {
+ case 'b':
+ case 'c':
+ case 'f':
+ case 'v':
+ case 'S':
+ ++i;
+ break;
+ }
+ }
+
+ /*
+ * Create arguments early and define it to root it, so it's safe from any
+ * GC calls nested below, and so it is available to -f <file> arguments.
+ */
+ argsObj = JS_NewArrayObject(cx, 0, NULL);
+ if (!argsObj)
+ return 1;
+ if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj),
+ NULL, NULL, 0)) {
+ return 1;
+ }
+
+ length = argc - i;
+ for (j = 0; j < length; j++) {
+ JSString *str = JS_NewStringCopyZ(cx, argv[i++]);
+ if (!str)
+ return 1;
+ if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return 1;
+ }
+ }
+
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] != '-' || argv[i][1] == '\0') {
+ filename = argv[i++];
+ isInteractive = JS_FALSE;
+ break;
+ }
+
+ switch (argv[i][1]) {
+ case 'v':
+ if (++i == argc) {
+ return usage();
+ }
+ JS_SetVersion(cx, (JSVersion) atoi(argv[i]));
+ break;
+
+ case 'w':
+ reportWarnings = JS_TRUE;
+ break;
+
+ case 'W':
+ reportWarnings = JS_FALSE;
+ break;
+
+ case 's':
+ JS_ToggleOptions(cx, JSOPTION_STRICT);
+ break;
+
+ case 'P':
+ if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) {
+ JSObject *gobj;
+
+ if (!JS_SealObject(cx, obj, JS_TRUE))
+ return JS_FALSE;
+ gobj = JS_NewObject(cx, &global_class, NULL, NULL);
+ if (!gobj)
+ return JS_FALSE;
+ if (!JS_SetPrototype(cx, gobj, obj))
+ return JS_FALSE;
+ JS_SetParent(cx, gobj, NULL);
+ JS_SetGlobalObject(cx, gobj);
+ obj = gobj;
+ }
+ break;
+
+ case 'b':
+ gBranchLimit = atoi(argv[++i]);
+ JS_SetBranchCallback(cx, my_BranchCallback);
+ break;
+
+ case 'c':
+ /* set stack chunk size */
+ gStackChunkSize = atoi(argv[++i]);
+ break;
+
+ case 'f':
+ if (++i == argc) {
+ return usage();
+ }
+ Process(cx, obj, argv[i]);
+ /*
+ * XXX: js -f foo.js should interpret foo.js and then
+ * drop into interactive mode, but that breaks test
+ * harness. Just execute foo.js for now.
+ */
+ isInteractive = JS_FALSE;
+ break;
+
+ case 'S':
+ if (++i == argc) {
+ return usage();
+ }
+ /* Set maximum stack size. */
+ gMaxStackSize = atoi(argv[i]);
+ break;
+
+ default:
+ return usage();
+ }
+ }
+
+ if (filename || isInteractive)
+ Process(cx, obj, filename);
+ return gExitCode;
+}
+
+
+static JSBool
+Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (argc > 0 && JSVAL_IS_INT(argv[0]))
+ *rval = INT_TO_JSVAL(JS_SetVersion(cx, (JSVersion) JSVAL_TO_INT(argv[0])));
+ else
+ *rval = INT_TO_JSVAL(JS_GetVersion(cx));
+ return JS_TRUE;
+}
+
+static struct {
+ const char *name;
+ uint32 flag;
+} js_options[] = {
+ {"strict", JSOPTION_STRICT},
+ {"werror", JSOPTION_WERROR},
+ {0, 0}
+};
+
+static JSBool
+Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ uint32 optset, flag;
+ uintN i, j, found;
+ JSString *str;
+ const char *opt;
+ char *names;
+
+ optset = 0;
+ for (i = 0; i < argc; i++) {
+ str = JS_ValueToString(cx, argv[i]);
+ if (!str)
+ return JS_FALSE;
+ opt = JS_GetStringBytes(str);
+ for (j = 0; js_options[j].name; j++) {
+ if (strcmp(js_options[j].name, opt) == 0) {
+ optset |= js_options[j].flag;
+ break;
+ }
+ }
+ }
+ optset = JS_ToggleOptions(cx, optset);
+
+ names = NULL;
+ found = 0;
+ while (optset != 0) {
+ flag = optset;
+ optset &= optset - 1;
+ flag &= ~optset;
+ for (j = 0; js_options[j].name; j++) {
+ if (js_options[j].flag == flag) {
+ names = JS_sprintf_append(names, "%s%s",
+ names ? "," : "", js_options[j].name);
+ found++;
+ break;
+ }
+ }
+ }
+ if (!found)
+ names = strdup("");
+ if (!names) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+
+ str = JS_NewString(cx, names, strlen(names));
+ if (!str) {
+ free(names);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static void
+my_LoadErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
+
+static void
+my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
+
+static JSBool
+Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ uintN i;
+ JSString *str;
+ const char *filename;
+ JSScript *script;
+ JSBool ok;
+ jsval result;
+ JSErrorReporter older;
+
+ for (i = 0; i < argc; i++) {
+ str = JS_ValueToString(cx, argv[i]);
+ if (!str)
+ return JS_FALSE;
+ argv[i] = STRING_TO_JSVAL(str);
+ filename = JS_GetStringBytes(str);
+ errno = 0;
+ older = JS_SetErrorReporter(cx, my_LoadErrorReporter);
+ script = JS_CompileFile(cx, obj, filename);
+ if (!script)
+ ok = JS_FALSE;
+ else {
+ ok = JS_ExecuteScript(cx, obj, script, &result);
+ JS_DestroyScript(cx, script);
+ }
+ JS_SetErrorReporter(cx, older);
+ if (!ok)
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ uintN i, n;
+ JSString *str;
+
+ for (i = n = 0; i < argc; i++) {
+ str = JS_ValueToString(cx, argv[i]);
+ if (!str)
+ return JS_FALSE;
+ fprintf(gOutFile, "%s%s", i ? " " : "", JS_GetStringBytes(str));
+ }
+ n++;
+ if (n)
+ fputc('\n', gOutFile);
+ return JS_TRUE;
+}
+
+static JSBool
+Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+static JSBool
+Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+#ifdef LIVECONNECT
+ JSJ_SimpleShutdown();
+#endif
+
+ JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode);
+
+ gQuitting = JS_TRUE;
+ return JS_FALSE;
+}
+
+#ifdef GC_MARK_DEBUG
+extern JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
+#endif
+
+static JSBool
+GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSRuntime *rt;
+ uint32 preBytes;
+
+ rt = cx->runtime;
+ preBytes = rt->gcBytes;
+#ifdef GC_MARK_DEBUG
+ if (argc && JSVAL_IS_STRING(argv[0])) {
+ char *name = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
+ FILE *file = fopen(name, "w");
+ if (!file) {
+ fprintf(gErrFile, "gc: can't open %s: %s\n", strerror(errno));
+ return JS_FALSE;
+ }
+ js_DumpGCHeap = file;
+ } else {
+ js_DumpGCHeap = stdout;
+ }
+#endif
+ JS_GC(cx);
+#ifdef GC_MARK_DEBUG
+ if (js_DumpGCHeap != stdout)
+ fclose(js_DumpGCHeap);
+ js_DumpGCHeap = NULL;
+#endif
+ fprintf(gOutFile, "before %lu, after %lu, break %08lx\n",
+ (unsigned long)preBytes, (unsigned long)rt->gcBytes,
+#ifdef XP_UNIX
+ (unsigned long)sbrk(0)
+#else
+ 0
+#endif
+ );
+#ifdef JS_GCMETER
+ js_DumpGCStats(rt, stdout);
+#endif
+ return JS_TRUE;
+}
+
+static JSScript *
+ValueToScript(JSContext *cx, jsval v)
+{
+ JSScript *script;
+ JSFunction *fun;
+
+ if (JSVAL_IS_OBJECT(v) &&
+ JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass) {
+ script = (JSScript *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ } else {
+ fun = JS_ValueToFunction(cx, v);
+ if (!fun)
+ return NULL;
+ script = fun->script;
+ }
+ return script;
+}
+
+static JSBool
+GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
+ int32 *ip)
+{
+ uintN intarg;
+ JSScript *script;
+
+ *scriptp = cx->fp->down->script;
+ *ip = 0;
+ if (argc != 0) {
+ intarg = 0;
+ if (JS_TypeOfValue(cx, argv[0]) == JSTYPE_FUNCTION) {
+ script = ValueToScript(cx, argv[0]);
+ if (!script)
+ return JS_FALSE;
+ *scriptp = script;
+ intarg++;
+ }
+ if (argc > intarg) {
+ if (!JS_ValueToInt32(cx, argv[intarg], ip))
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSTrapStatus
+TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
+ void *closure)
+{
+ JSString *str;
+ JSStackFrame *caller;
+
+ str = (JSString *) closure;
+ caller = JS_GetScriptedCaller(cx, NULL);
+ if (!JS_EvaluateScript(cx, caller->scopeChain,
+ JS_GetStringBytes(str), JS_GetStringLength(str),
+ caller->script->filename, caller->script->lineno,
+ rval)) {
+ return JSTRAP_ERROR;
+ }
+ if (*rval != JSVAL_VOID)
+ return JSTRAP_RETURN;
+ return JSTRAP_CONTINUE;
+}
+
+static JSBool
+Trap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ JSScript *script;
+ int32 i;
+
+ if (argc == 0) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_TRAP_USAGE);
+ return JS_FALSE;
+ }
+ argc--;
+ str = JS_ValueToString(cx, argv[argc]);
+ if (!str)
+ return JS_FALSE;
+ argv[argc] = STRING_TO_JSVAL(str);
+ if (!GetTrapArgs(cx, argc, argv, &script, &i))
+ return JS_FALSE;
+ return JS_SetTrap(cx, script, script->code + i, TrapHandler, str);
+}
+
+static JSBool
+Untrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSScript *script;
+ int32 i;
+
+ if (!GetTrapArgs(cx, argc, argv, &script, &i))
+ return JS_FALSE;
+ JS_ClearTrap(cx, script, script->code + i, NULL, NULL);
+ return JS_TRUE;
+}
+
+static JSBool
+LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSScript *script;
+ int32 i;
+ uintN lineno;
+ jsbytecode *pc;
+
+ if (argc == 0) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
+ return JS_FALSE;
+ }
+ script = cx->fp->down->script;
+ if (!GetTrapArgs(cx, argc, argv, &script, &i))
+ return JS_FALSE;
+ lineno = (i == 0) ? script->lineno : (uintN)i;
+ pc = JS_LineNumberToPC(cx, script, lineno);
+ if (!pc)
+ return JS_FALSE;
+ *rval = INT_TO_JSVAL(PTRDIFF(pc, script->code, jsbytecode));
+ return JS_TRUE;
+}
+
+static JSBool
+PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSScript *script;
+ int32 i;
+ uintN lineno;
+
+ if (!GetTrapArgs(cx, argc, argv, &script, &i))
+ return JS_FALSE;
+ lineno = JS_PCToLineNumber(cx, script, script->code + i);
+ if (!lineno)
+ return JS_FALSE;
+ *rval = INT_TO_JSVAL(lineno);
+ return JS_TRUE;
+}
+
+#ifdef DEBUG
+
+static void
+SrcNotes(JSContext *cx, JSScript *script)
+{
+ uintN offset, delta, caseOff;
+ jssrcnote *notes, *sn;
+ JSSrcNoteType type;
+ jsatomid atomIndex;
+ JSAtom *atom;
+
+ fprintf(gOutFile, "\nSource notes:\n");
+ offset = 0;
+ notes = SCRIPT_NOTES(script);
+ for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
+ delta = SN_DELTA(sn);
+ offset += delta;
+ fprintf(gOutFile, "%3u: %5u [%4u] %-8s",
+ PTRDIFF(sn, notes, jssrcnote), offset, delta,
+ js_SrcNoteSpec[SN_TYPE(sn)].name);
+ type = (JSSrcNoteType) SN_TYPE(sn);
+ switch (type) {
+ case SRC_SETLINE:
+ fprintf(gOutFile, " lineno %u", (uintN) js_GetSrcNoteOffset(sn, 0));
+ break;
+ case SRC_FOR:
+ fprintf(gOutFile, " cond %u update %u tail %u",
+ (uintN) js_GetSrcNoteOffset(sn, 0),
+ (uintN) js_GetSrcNoteOffset(sn, 1),
+ (uintN) js_GetSrcNoteOffset(sn, 2));
+ break;
+ case SRC_COND:
+ case SRC_IF_ELSE:
+ case SRC_WHILE:
+ case SRC_PCBASE:
+ case SRC_PCDELTA:
+ fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0));
+ break;
+ case SRC_LABEL:
+ case SRC_LABELBRACE:
+ case SRC_BREAK2LABEL:
+ case SRC_CONT2LABEL:
+ case SRC_FUNCDEF: {
+ const char *bytes;
+ JSFunction *fun;
+ JSString *str;
+
+ atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0);
+ atom = js_GetAtom(cx, &script->atomMap, atomIndex);
+ if (type != SRC_FUNCDEF) {
+ bytes = js_AtomToPrintableString(cx, atom);
+ } else {
+ fun = (JSFunction *)
+ JS_GetPrivate(cx, ATOM_TO_OBJECT(atom));
+ str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
+ bytes = str ? JS_GetStringBytes(str) : "N/A";
+ }
+ fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes);
+ break;
+ }
+ case SRC_SWITCH:
+ fprintf(gOutFile, " length %u", (uintN) js_GetSrcNoteOffset(sn, 0));
+ caseOff = (uintN) js_GetSrcNoteOffset(sn, 1);
+ if (caseOff)
+ fprintf(gOutFile, " first case offset %u", caseOff);
+ break;
+ case SRC_CATCH:
+ delta = (uintN) js_GetSrcNoteOffset(sn, 0);
+ if (delta)
+ fprintf(gOutFile, " guard size %u", delta);
+ break;
+ default:;
+ }
+ fputc('\n', gOutFile);
+ }
+}
+
+static JSBool
+Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ uintN i;
+ JSScript *script;
+
+ for (i = 0; i < argc; i++) {
+ script = ValueToScript(cx, argv[i]);
+ if (!script)
+ continue;
+
+ SrcNotes(cx, script);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+TryNotes(JSContext *cx, JSScript *script)
+{
+ JSTryNote *tn = script->trynotes;
+
+ if (!tn)
+ return JS_TRUE;
+ fprintf(gOutFile, "\nException table:\nstart\tend\tcatch\n");
+ while (tn->start && tn->catchStart) {
+ fprintf(gOutFile, " %d\t%d\t%d\n",
+ tn->start, tn->start + tn->length, tn->catchStart);
+ tn++;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSBool lines;
+ uintN i;
+ JSScript *script;
+
+ if (argc > 0 &&
+ JSVAL_IS_STRING(argv[0]) &&
+ !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), "-l")) {
+ lines = JS_TRUE;
+ argv++, argc--;
+ } else {
+ lines = JS_FALSE;
+ }
+ for (i = 0; i < argc; i++) {
+ script = ValueToScript(cx, argv[i]);
+ if (!script)
+ continue;
+
+ if (JSVAL_IS_FUNCTION(cx, argv[i])) {
+ JSFunction *fun = JS_ValueToFunction(cx, argv[i]);
+ if (fun && (fun->flags & JSFUN_FLAGS_MASK)) {
+ uint8 flags = fun->flags;
+ fputs("flags:", stdout);
+
+#define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout);
+
+ SHOW_FLAG(LAMBDA);
+ SHOW_FLAG(SETTER);
+ SHOW_FLAG(GETTER);
+ SHOW_FLAG(BOUND_METHOD);
+ SHOW_FLAG(HEAVYWEIGHT);
+
+#undef SHOW_FLAG
+ putchar('\n');
+ }
+ }
+
+ js_Disassemble(cx, script, lines, stdout);
+ SrcNotes(cx, script);
+ TryNotes(cx, script);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+#define LINE_BUF_LEN 512
+ uintN i, len, line1, line2, bupline;
+ JSScript *script;
+ FILE *file;
+ char linebuf[LINE_BUF_LEN];
+ jsbytecode *pc, *end;
+ static char sep[] = ";-------------------------";
+
+ for (i = 0; i < argc; i++) {
+ script = ValueToScript(cx, argv[i]);
+ if (!script)
+ continue;
+
+ if (!script || !script->filename) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
+ JSSMSG_FILE_SCRIPTS_ONLY);
+ return JS_FALSE;
+ }
+
+ file = fopen(script->filename, "r");
+ if (!file) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
+ JSSMSG_CANT_OPEN,
+ script->filename, strerror(errno));
+ return JS_FALSE;
+ }
+
+ pc = script->code;
+ end = pc + script->length;
+
+ /* burn the leading lines */
+ line2 = JS_PCToLineNumber(cx, script, pc);
+ for (line1 = 0; line1 < line2 - 1; line1++)
+ fgets(linebuf, LINE_BUF_LEN, file);
+
+ bupline = 0;
+ while (pc < end) {
+ line2 = JS_PCToLineNumber(cx, script, pc);
+
+ if (line2 < line1) {
+ if (bupline != line2) {
+ bupline = line2;
+ fprintf(gOutFile, "%s %3u: BACKUP\n", sep, line2);
+ }
+ } else {
+ if (bupline && line1 == line2)
+ fprintf(gOutFile, "%s %3u: RESTORE\n", sep, line2);
+ bupline = 0;
+ while (line1 < line2) {
+ if (!fgets(linebuf, LINE_BUF_LEN, file)) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
+ JSSMSG_UNEXPECTED_EOF,
+ script->filename);
+ goto bail;
+ }
+ line1++;
+ fprintf(gOutFile, "%s %3u: %s", sep, line1, linebuf);
+ }
+ }
+
+ len = js_Disassemble1(cx, script, pc,
+ PTRDIFF(pc, script->code, jsbytecode),
+ JS_TRUE, stdout);
+ if (!len)
+ return JS_FALSE;
+ pc += len;
+ }
+
+ bail:
+ fclose(file);
+ }
+ return JS_TRUE;
+#undef LINE_BUF_LEN
+}
+
+static JSBool
+Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSBool bval;
+ JSString *str;
+
+ if (argc == 0) {
+ *rval = BOOLEAN_TO_JSVAL(cx->tracefp != 0);
+ return JS_TRUE;
+ }
+
+ switch (JS_TypeOfValue(cx, argv[0])) {
+ case JSTYPE_NUMBER:
+ bval = JSVAL_IS_INT(argv[0])
+ ? JSVAL_TO_INT(argv[0])
+ : (jsint) *JSVAL_TO_DOUBLE(argv[0]);
+ break;
+ case JSTYPE_BOOLEAN:
+ bval = JSVAL_TO_BOOLEAN(argv[0]);
+ break;
+ default:
+ str = JS_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ fprintf(gErrFile, "tracing: illegal argument %s\n",
+ JS_GetStringBytes(str));
+ return JS_TRUE;
+ }
+ cx->tracefp = bval ? stderr : NULL;
+ return JS_TRUE;
+}
+
+typedef struct DumpAtomArgs {
+ JSContext *cx;
+ FILE *fp;
+} DumpAtomArgs;
+
+static int
+DumpAtom(JSHashEntry *he, int i, void *arg)
+{
+ DumpAtomArgs *args = (DumpAtomArgs *)arg;
+ FILE *fp = args->fp;
+ JSAtom *atom = (JSAtom *)he;
+
+ fprintf(fp, "%3d %08x %5lu ",
+ i, (uintN)he->keyHash, (unsigned long)atom->number);
+ if (ATOM_IS_STRING(atom))
+ fprintf(fp, "\"%s\"\n", js_AtomToPrintableString(args->cx, atom));
+ else if (ATOM_IS_INT(atom))
+ fprintf(fp, "%ld\n", (long)ATOM_TO_INT(atom));
+ else
+ fprintf(fp, "%.16g\n", *ATOM_TO_DOUBLE(atom));
+ return HT_ENUMERATE_NEXT;
+}
+
+static void
+DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
+{
+ uintN i;
+ JSScope *scope;
+ JSScopeProperty *sprop;
+
+ i = 0;
+ scope = OBJ_SCOPE(obj);
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
+ continue;
+ fprintf(fp, "%3u %p", i, sprop);
+ if (JSVAL_IS_INT(sprop->id)) {
+ fprintf(fp, " [%ld]", (long)JSVAL_TO_INT(sprop->id));
+ } else {
+ fprintf(fp, " \"%s\"",
+ js_AtomToPrintableString(cx, (JSAtom *)sprop->id));
+ }
+
+#define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
+ DUMP_ATTR(ENUMERATE);
+ DUMP_ATTR(READONLY);
+ DUMP_ATTR(PERMANENT);
+ DUMP_ATTR(EXPORTED);
+ DUMP_ATTR(GETTER);
+ DUMP_ATTR(SETTER);
+#undef DUMP_ATTR
+
+ fprintf(fp, " slot %lu flags %x shortid %d\n",
+ sprop->slot, sprop->flags, sprop->shortid);
+ }
+}
+
+static JSBool
+DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ uintN i;
+ JSString *str;
+ const char *bytes;
+ JSAtom *atom;
+ JSObject *obj2;
+ JSProperty *prop;
+ jsval value;
+
+ for (i = 0; i < argc; i++) {
+ str = JS_ValueToString(cx, argv[i]);
+ if (!str)
+ return JS_FALSE;
+ bytes = JS_GetStringBytes(str);
+ if (strcmp(bytes, "arena") == 0) {
+#ifdef JS_ARENAMETER
+ JS_DumpArenaStats(stdout);
+#endif
+ } else if (strcmp(bytes, "atom") == 0) {
+ DumpAtomArgs args;
+
+ fprintf(gOutFile, "\natom table contents:\n");
+ args.cx = cx;
+ args.fp = stdout;
+ JS_HashTableEnumerateEntries(cx->runtime->atomState.table,
+ DumpAtom,
+ &args);
+#ifdef HASHMETER
+ JS_HashTableDumpMeter(cx->runtime->atomState.table,
+ DumpAtom,
+ stdout);
+#endif
+ } else if (strcmp(bytes, "global") == 0) {
+ DumpScope(cx, cx->globalObject, stdout);
+ } else {
+ atom = js_Atomize(cx, bytes, JS_GetStringLength(str), 0);
+ if (!atom)
+ return JS_FALSE;
+ if (!js_FindProperty(cx, (jsid)atom, &obj, &obj2, &prop))
+ return JS_FALSE;
+ if (prop) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ if (!OBJ_GET_PROPERTY(cx, obj, (jsid)atom, &value))
+ return JS_FALSE;
+ }
+ if (!prop || !JSVAL_IS_OBJECT(value)) {
+ fprintf(gErrFile, "js: invalid stats argument %s\n",
+ bytes);
+ continue;
+ }
+ obj = JSVAL_TO_OBJECT(value);
+ if (obj)
+ DumpScope(cx, obj, stdout);
+ }
+ }
+ return JS_TRUE;
+}
+
+#endif /* DEBUG */
+
+#ifdef TEST_EXPORT
+static JSBool
+DoExport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSAtom *atom;
+ JSObject *obj2;
+ JSProperty *prop;
+ JSBool ok;
+ uintN attrs;
+
+ if (argc != 2) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_DOEXP_USAGE);
+ return JS_FALSE;
+ }
+ if (!JS_ValueToObject(cx, argv[0], &obj))
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(obj);
+ atom = js_ValueToStringAtom(cx, argv[1]);
+ if (!atom)
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
+ JSPROP_EXPORTED, NULL);
+ } else {
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
+ if (ok) {
+ attrs |= JSPROP_EXPORTED;
+ ok = OBJ_SET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ }
+ return ok;
+}
+#endif
+
+#ifdef TEST_CVTARGS
+#include <ctype.h>
+
+static const char *
+EscapeWideString(jschar *w)
+{
+ static char enuf[80];
+ static char hex[] = "0123456789abcdef";
+ jschar u;
+ unsigned char b, c;
+ int i, j;
+
+ if (!w)
+ return "";
+ for (i = j = 0; i < sizeof enuf - 1; i++, j++) {
+ u = w[j];
+ if (u == 0)
+ break;
+ b = (unsigned char)(u >> 8);
+ c = (unsigned char)(u);
+ if (b) {
+ if (i >= sizeof enuf - 6)
+ break;
+ enuf[i++] = '\\';
+ enuf[i++] = 'u';
+ enuf[i++] = hex[b >> 4];
+ enuf[i++] = hex[b & 15];
+ enuf[i++] = hex[c >> 4];
+ enuf[i] = hex[c & 15];
+ } else if (!isprint(c)) {
+ if (i >= sizeof enuf - 4)
+ break;
+ enuf[i++] = '\\';
+ enuf[i++] = 'x';
+ enuf[i++] = hex[c >> 4];
+ enuf[i] = hex[c & 15];
+ } else {
+ enuf[i] = (char)c;
+ }
+ }
+ enuf[i] = 0;
+ return enuf;
+}
+
+#include <stdarg.h>
+
+static JSBool
+ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp,
+ va_list *app)
+{
+ jsval *vp;
+ va_list ap;
+ jsdouble re, im;
+
+ printf("entering ZZ_formatter");
+ vp = *vpp;
+ ap = *app;
+ if (fromJS) {
+ if (!JS_ValueToNumber(cx, vp[0], &re))
+ return JS_FALSE;
+ if (!JS_ValueToNumber(cx, vp[1], &im))
+ return JS_FALSE;
+ *va_arg(ap, jsdouble *) = re;
+ *va_arg(ap, jsdouble *) = im;
+ } else {
+ re = va_arg(ap, jsdouble);
+ im = va_arg(ap, jsdouble);
+ if (!JS_NewNumberValue(cx, re, &vp[0]))
+ return JS_FALSE;
+ if (!JS_NewNumberValue(cx, im, &vp[1]))
+ return JS_FALSE;
+ }
+ *vpp = vp + 2;
+ *app = ap;
+ printf("leaving ZZ_formatter");
+ return JS_TRUE;
+}
+
+static JSBool
+ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSBool b = JS_FALSE;
+ jschar c = 0;
+ int32 i = 0, j = 0;
+ uint32 u = 0;
+ jsdouble d = 0, I = 0, re = 0, im = 0;
+ char *s = NULL;
+ JSString *str = NULL;
+ jschar *w = NULL;
+ JSObject *obj2 = NULL;
+ JSFunction *fun = NULL;
+ jsval v = JSVAL_VOID;
+ JSBool ok;
+
+ if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter))
+ return JS_FALSE;;
+ ok = JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofvZZ*",
+ &b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj2,
+ &fun, &v, &re, &im);
+ JS_RemoveArgumentFormatter(cx, "ZZ");
+ if (!ok)
+ return JS_FALSE;
+ fprintf(gOutFile,
+ "b %u, c %x (%c), i %ld, u %lu, j %ld\n",
+ b, c, (char)c, i, u, j);
+ fprintf(gOutFile,
+ "d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n"
+ "v %s, re %g, im %g\n",
+ d, I, s, str ? JS_GetStringBytes(str) : "", EscapeWideString(w),
+ JS_GetStringBytes(JS_ValueToString(cx, OBJECT_TO_JSVAL(obj2))),
+ fun ? JS_GetStringBytes(JS_DecompileFunction(cx, fun, 4)) : "",
+ JS_GetStringBytes(JS_ValueToString(cx, v)), re, im);
+ return JS_TRUE;
+}
+#endif
+
+static JSBool
+BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ fprintf(gOutFile, "built on %s at %s\n", __DATE__, __TIME__);
+ return JS_TRUE;
+}
+
+static JSBool
+Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (argc != 0 && !JS_ValueToObject(cx, argv[0], &obj))
+ return JS_FALSE;
+ JS_ClearScope(cx, obj);
+ return JS_TRUE;
+}
+
+static JSBool
+Intern(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+
+ str = JS_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ if (!JS_InternUCStringN(cx, JS_GetStringChars(str),
+ JS_GetStringLength(str))) {
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFunction *fun;
+ JSObject *funobj, *parent, *clone;
+
+ fun = JS_ValueToFunction(cx, argv[0]);
+ if (!fun)
+ return JS_FALSE;
+ funobj = JS_GetFunctionObject(fun);
+ if (argc > 1) {
+ if (!JS_ValueToObject(cx, argv[1], &parent))
+ return JS_FALSE;
+ } else {
+ parent = JS_GetParent(cx, funobj);
+ }
+ clone = JS_CloneFunctionObject(cx, funobj, parent);
+ if (!clone)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(clone);
+ return JS_TRUE;
+}
+
+static JSBool
+Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSObject *target;
+ JSBool deep = JS_FALSE;
+
+ if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
+ return JS_FALSE;
+ if (!target)
+ return JS_TRUE;
+ return JS_SealObject(cx, target, deep);
+}
+
+static JSFunctionSpec shell_functions[] = {
+ {"version", Version, 0},
+ {"options", Options, 0},
+ {"load", Load, 1},
+ {"print", Print, 0},
+ {"help", Help, 0},
+ {"quit", Quit, 0},
+ {"gc", GC, 0},
+ {"trap", Trap, 3},
+ {"untrap", Untrap, 2},
+ {"line2pc", LineToPC, 0},
+ {"pc2line", PCToLine, 0},
+#ifdef DEBUG
+ {"dis", Disassemble, 1},
+ {"dissrc", DisassWithSrc, 1},
+ {"notes", Notes, 1},
+ {"tracing", Tracing, 0},
+ {"stats", DumpStats, 1},
+#endif
+#ifdef TEST_EXPORT
+ {"xport", DoExport, 2},
+#endif
+#ifdef TEST_CVTARGS
+ {"cvtargs", ConvertArgs, 0, 0, 12},
+#endif
+ {"build", BuildDate, 0},
+ {"clear", Clear, 0},
+ {"intern", Intern, 1},
+ {"clone", Clone, 1},
+ {"seal", Seal, 1, 0, 1},
+ {0}
+};
+
+/* NOTE: These must be kept in sync with the above. */
+
+static char *shell_help_messages[] = {
+ "version([number]) Get or set JavaScript version number",
+ "options([option ...]) Get or toggle JavaScript options",
+ "load(['foo.js' ...]) Load files named by string arguments",
+ "print([exp ...]) Evaluate and print expressions",
+ "help([name ...]) Display usage and help messages",
+ "quit() Quit the shell",
+ "gc() Run the garbage collector",
+ "trap([fun, [pc,]] exp) Trap bytecode execution",
+ "untrap(fun[, pc]) Remove a trap",
+ "line2pc([fun,] line) Map line number to PC",
+ "pc2line(fun[, pc]) Map PC to line number",
+#ifdef DEBUG
+ "dis([fun]) Disassemble functions into bytecodes",
+ "dissrc([fun]) Disassemble functions with source lines",
+ "notes([fun]) Show source notes for functions",
+ "tracing([toggle]) Turn tracing on or off",
+ "stats([string ...]) Dump 'arena', 'atom', 'global' stats",
+#endif
+#ifdef TEST_EXPORT
+ "xport(obj, id) Export identified property from object",
+#endif
+#ifdef TEST_CVTARGS
+ "cvtargs(b, c, ...) Test JS_ConvertArguments",
+#endif
+ "build() Show build date and time",
+ "clear([obj]) Clear properties of object",
+ "intern(str) Internalize str in the atom table",
+ "clone(fun[, scope]) Clone function object",
+ "seal(obj[, deep]) Seal object, or object graph if deep",
+ 0
+};
+
+static void
+ShowHelpHeader(void)
+{
+ fprintf(gOutFile, "%-9s %-22s %s\n", "Command", "Usage", "Description");
+ fprintf(gOutFile, "%-9s %-22s %s\n", "=======", "=====", "===========");
+}
+
+static void
+ShowHelpForCommand(uintN n)
+{
+ fprintf(gOutFile, "%-9.9s %s\n", shell_functions[n].name, shell_help_messages[n]);
+}
+
+static JSBool
+Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ uintN i, j;
+ int did_header, did_something;
+ JSType type;
+ JSFunction *fun;
+ JSString *str;
+ const char *bytes;
+
+ fprintf(gOutFile, "%s\n", JS_GetImplementationVersion());
+ if (argc == 0) {
+ ShowHelpHeader();
+ for (i = 0; shell_functions[i].name; i++)
+ ShowHelpForCommand(i);
+ } else {
+ did_header = 0;
+ for (i = 0; i < argc; i++) {
+ did_something = 0;
+ type = JS_TypeOfValue(cx, argv[i]);
+ if (type == JSTYPE_FUNCTION) {
+ fun = JS_ValueToFunction(cx, argv[i]);
+ str = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
+ } else if (type == JSTYPE_STRING) {
+ str = JSVAL_TO_STRING(argv[i]);
+ } else {
+ str = NULL;
+ }
+ if (str) {
+ bytes = JS_GetStringBytes(str);
+ for (j = 0; shell_functions[j].name; j++) {
+ if (!strcmp(bytes, shell_functions[j].name)) {
+ if (!did_header) {
+ did_header = 1;
+ ShowHelpHeader();
+ }
+ did_something = 1;
+ ShowHelpForCommand(j);
+ break;
+ }
+ }
+ }
+ if (!did_something) {
+ str = JS_ValueToString(cx, argv[i]);
+ if (!str)
+ return JS_FALSE;
+ fprintf(gErrFile, "Sorry, no help for %s\n",
+ JS_GetStringBytes(str));
+ }
+ }
+ }
+ return JS_TRUE;
+}
+
+/*
+ * Define a JS object called "it". Give it class operations that printf why
+ * they're being called for tutorial purposes.
+ */
+enum its_tinyid {
+ ITS_COLOR, ITS_HEIGHT, ITS_WIDTH, ITS_FUNNY, ITS_ARRAY, ITS_RDONLY
+};
+
+static JSPropertySpec its_props[] = {
+ {"color", ITS_COLOR, JSPROP_ENUMERATE},
+ {"height", ITS_HEIGHT, JSPROP_ENUMERATE},
+ {"width", ITS_WIDTH, JSPROP_ENUMERATE},
+ {"funny", ITS_FUNNY, JSPROP_ENUMERATE},
+ {"array", ITS_ARRAY, JSPROP_ENUMERATE},
+ {"rdonly", ITS_RDONLY, JSPROP_READONLY},
+ {0}
+};
+
+static JSBool
+its_item(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ *rval = OBJECT_TO_JSVAL(obj);
+ if (argc != 0)
+ JS_SetCallReturnValue2(cx, argv[0]);
+ return JS_TRUE;
+}
+
+static JSFunctionSpec its_methods[] = {
+ {"item", its_item, 0},
+ {0}
+};
+
+#ifdef JSD_LOWLEVEL_SOURCE
+/*
+ * This facilitates sending source to JSD (the debugger system) in the shell
+ * where the source is loaded using the JSFILE hack in jsscan. The function
+ * below is used as a callback for the jsdbgapi JS_SetSourceHandler hook.
+ * A more normal embedding (e.g. mozilla) loads source itself and can send
+ * source directly to JSD without using this hook scheme.
+ */
+static void
+SendSourceToJSDebugger(const char *filename, uintN lineno,
+ jschar *str, size_t length,
+ void **listenerTSData, JSDContext* jsdc)
+{
+ JSDSourceText *jsdsrc = (JSDSourceText *) *listenerTSData;
+
+ if (!jsdsrc) {
+ if (!filename)
+ filename = "typein";
+ if (1 == lineno) {
+ jsdsrc = JSD_NewSourceText(jsdc, filename);
+ } else {
+ jsdsrc = JSD_FindSourceForURL(jsdc, filename);
+ if (jsdsrc && JSD_SOURCE_PARTIAL !=
+ JSD_GetSourceStatus(jsdc, jsdsrc)) {
+ jsdsrc = NULL;
+ }
+ }
+ }
+ if (jsdsrc) {
+ jsdsrc = JSD_AppendUCSourceText(jsdc,jsdsrc, str, length,
+ JSD_SOURCE_PARTIAL);
+ }
+ *listenerTSData = jsdsrc;
+}
+#endif /* JSD_LOWLEVEL_SOURCE */
+
+static JSBool its_noisy; /* whether to be noisy when finalizing it */
+
+static JSBool
+its_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ if (its_noisy) {
+ fprintf(gOutFile, "adding its property %s,",
+ JS_GetStringBytes(JS_ValueToString(cx, id)));
+ fprintf(gOutFile, " initial value %s\n",
+ JS_GetStringBytes(JS_ValueToString(cx, *vp)));
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+its_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ if (its_noisy) {
+ fprintf(gOutFile, "deleting its property %s,",
+ JS_GetStringBytes(JS_ValueToString(cx, id)));
+ fprintf(gOutFile, " current value %s\n",
+ JS_GetStringBytes(JS_ValueToString(cx, *vp)));
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+its_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ if (its_noisy) {
+ fprintf(gOutFile, "getting its property %s,",
+ JS_GetStringBytes(JS_ValueToString(cx, id)));
+ fprintf(gOutFile, " current value %s\n",
+ JS_GetStringBytes(JS_ValueToString(cx, *vp)));
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+its_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ if (its_noisy) {
+ fprintf(gOutFile, "setting its property %s,",
+ JS_GetStringBytes(JS_ValueToString(cx, id)));
+ fprintf(gOutFile, " new value %s\n",
+ JS_GetStringBytes(JS_ValueToString(cx, *vp)));
+ }
+ if (JSVAL_IS_STRING(id) &&
+ !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(id)), "noisy")) {
+ return JS_ValueToBoolean(cx, *vp, &its_noisy);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+its_enumerate(JSContext *cx, JSObject *obj)
+{
+ if (its_noisy)
+ fprintf(gOutFile, "enumerate its properties\n");
+ return JS_TRUE;
+}
+
+static JSBool
+its_resolve(JSContext *cx, JSObject *obj, jsval id)
+{
+ if (its_noisy) {
+ fprintf(gOutFile, "resolving its property %s\n",
+ JS_GetStringBytes(JS_ValueToString(cx, id)));
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+its_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+{
+ if (its_noisy)
+ fprintf(gOutFile, "converting it to %s type\n", JS_GetTypeName(cx, type));
+ return JS_TRUE;
+}
+
+static void
+its_finalize(JSContext *cx, JSObject *obj)
+{
+ if (its_noisy)
+ fprintf(gOutFile, "finalizing it\n");
+}
+
+static JSClass its_class = {
+ "It", 0,
+ its_addProperty, its_delProperty, its_getProperty, its_setProperty,
+ its_enumerate, its_resolve, its_convert, its_finalize
+};
+
+JSErrorFormatString jsShell_ErrorFormatString[JSErr_Limit] = {
+#if JS_HAS_DFLT_MSG_STRINGS
+#define MSG_DEF(name, number, count, exception, format) \
+ { format, count } ,
+#else
+#define MSG_DEF(name, number, count, exception, format) \
+ { NULL, count } ,
+#endif
+#include "jsshell.msg"
+#undef MSG_DEF
+};
+
+static const JSErrorFormatString *
+my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
+{
+ if ((errorNumber > 0) && (errorNumber < JSShellErr_Limit))
+ return &jsShell_ErrorFormatString[errorNumber];
+ return NULL;
+}
+
+static void
+my_LoadErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
+{
+ if (!report) {
+ fprintf(gErrFile, "%s\n", message);
+ return;
+ }
+
+ /* Ignore any exceptions */
+ if (JSREPORT_IS_EXCEPTION(report->flags))
+ return;
+
+ /* Otherwise, fall back to the ordinary error reporter. */
+ my_ErrorReporter(cx, message, report);
+}
+
+static void
+my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
+{
+ int i, j, k, n;
+ char *prefix, *tmp;
+ const char *ctmp;
+
+ if (!report) {
+ fprintf(gErrFile, "%s\n", message);
+ return;
+ }
+
+ /* Conditionally ignore reported warnings. */
+ if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
+ return;
+
+ prefix = NULL;
+ if (report->filename)
+ prefix = JS_smprintf("%s:", report->filename);
+ if (report->lineno) {
+ tmp = prefix;
+ prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno);
+ JS_free(cx, tmp);
+ }
+ if (JSREPORT_IS_WARNING(report->flags)) {
+ tmp = prefix;
+ prefix = JS_smprintf("%s%swarning: ",
+ tmp ? tmp : "",
+ JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
+ JS_free(cx, tmp);
+ }
+
+ /* embedded newlines -- argh! */
+ while ((ctmp = strchr(message, '\n')) != 0) {
+ ctmp++;
+ if (prefix)
+ fputs(prefix, gErrFile);
+ fwrite(message, 1, ctmp - message, gErrFile);
+ message = ctmp;
+ }
+
+ /* If there were no filename or lineno, the prefix might be empty */
+ if (prefix)
+ fputs(prefix, gErrFile);
+ fputs(message, gErrFile);
+
+ if (!report->linebuf) {
+ fputc('\n', gErrFile);
+ goto out;
+ }
+
+ /* report->linebuf usually ends with a newline. */
+ n = strlen(report->linebuf);
+ fprintf(gErrFile, ":\n%s%s%s%s",
+ prefix,
+ report->linebuf,
+ (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n",
+ prefix);
+ n = PTRDIFF(report->tokenptr, report->linebuf, char);
+ for (i = j = 0; i < n; i++) {
+ if (report->linebuf[i] == '\t') {
+ for (k = (j + 8) & ~7; j < k; j++) {
+ fputc('.', gErrFile);
+ }
+ continue;
+ }
+ fputc('.', gErrFile);
+ j++;
+ }
+ fputs("^\n", gErrFile);
+ out:
+ if (!JSREPORT_IS_WARNING(report->flags))
+ gExitCode = EXITCODE_RUNTIME_ERROR;
+ JS_free(cx, prefix);
+}
+
+#if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
+static JSBool
+Exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFunction *fun;
+ const char *name, **nargv;
+ uintN i, nargc;
+ JSString *str;
+ pid_t pid;
+ int status;
+
+ fun = JS_ValueToFunction(cx, argv[-2]);
+ if (!fun)
+ return JS_FALSE;
+ if (!fun->atom)
+ return JS_TRUE;
+ name = JS_GetStringBytes(ATOM_TO_STRING(fun->atom));
+ nargc = 1 + argc;
+ nargv = JS_malloc(cx, (nargc + 1) * sizeof(char *));
+ if (!nargv)
+ return JS_FALSE;
+ nargv[0] = name;
+ for (i = 1; i < nargc; i++) {
+ str = JS_ValueToString(cx, argv[i-1]);
+ if (!str) {
+ JS_free(cx, nargv);
+ return JS_FALSE;
+ }
+ nargv[i] = JS_GetStringBytes(str);
+ }
+ nargv[nargc] = 0;
+ pid = fork();
+ switch (pid) {
+ case -1:
+ perror("js");
+ break;
+ case 0:
+ (void) execvp(name, (char **)nargv);
+ perror("js");
+ exit(127);
+ default:
+ while (waitpid(pid, &status, 0) < 0 && errno == EINTR)
+ continue;
+ break;
+ }
+ JS_free(cx, nargv);
+ return JS_TRUE;
+}
+#endif
+
+#define LAZY_STANDARD_CLASSES
+
+static JSBool
+global_enumerate(JSContext *cx, JSObject *obj)
+{
+#ifdef LAZY_STANDARD_CLASSES
+ return JS_EnumerateStandardClasses(cx, obj);
+#else
+ return JS_TRUE;
+#endif
+}
+
+static JSBool
+global_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
+ JSObject **objp)
+{
+#ifdef LAZY_STANDARD_CLASSES
+ if ((flags & JSRESOLVE_ASSIGNING) == 0) {
+ JSBool resolved;
+
+ if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
+ return JS_FALSE;
+ if (resolved) {
+ *objp = obj;
+ return JS_TRUE;
+ }
+ }
+#endif
+
+#if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
+ if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) {
+ /*
+ * Do this expensive hack only for unoptimized Unix builds, which are
+ * not used for benchmarking.
+ */
+ char *path, *comp, *full;
+ const char *name;
+ JSBool ok, found;
+ JSFunction *fun;
+
+ if (!JSVAL_IS_STRING(id))
+ return JS_TRUE;
+ path = getenv("PATH");
+ if (!path)
+ return JS_TRUE;
+ path = JS_strdup(cx, path);
+ if (!path)
+ return JS_FALSE;
+ name = JS_GetStringBytes(JSVAL_TO_STRING(id));
+ ok = JS_TRUE;
+ for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) {
+ if (*comp != '\0') {
+ full = JS_smprintf("%s/%s", comp, name);
+ if (!full) {
+ JS_ReportOutOfMemory(cx);
+ ok = JS_FALSE;
+ break;
+ }
+ } else {
+ full = (char *)name;
+ }
+ found = (access(full, X_OK) == 0);
+ if (*comp != '\0')
+ free(full);
+ if (found) {
+ fun = JS_DefineFunction(cx, obj, name, Exec, 0,
+ JSPROP_ENUMERATE);
+ ok = (fun != NULL);
+ if (ok)
+ *objp = obj;
+ break;
+ }
+ }
+ JS_free(cx, path);
+ return ok;
+ }
+#else
+ return JS_TRUE;
+#endif
+}
+
+JSClass global_class = {
+ "global", JSCLASS_NEW_RESOLVE,
+ JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_PropertyStub,
+ global_enumerate, (JSResolveOp) global_resolve,
+ JS_ConvertStub, JS_FinalizeStub
+};
+
+static JSBool
+env_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+/* XXX porting may be easy, but these don't seem to supply setenv by default */
+#if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS
+ JSString *idstr, *valstr;
+ const char *name, *value;
+ int rv;
+
+ idstr = JS_ValueToString(cx, id);
+ valstr = JS_ValueToString(cx, *vp);
+ if (!idstr || !valstr)
+ return JS_FALSE;
+ name = JS_GetStringBytes(idstr);
+ value = JS_GetStringBytes(valstr);
+#if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX
+ {
+ char *waste = JS_smprintf("%s=%s", name, value);
+ if (!waste) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ rv = putenv(waste);
+#ifdef XP_WIN
+ /*
+ * HPUX9 at least still has the bad old non-copying putenv.
+ *
+ * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
+ * that will crash if you pass it an auto char array (so it must place
+ * its argument directly in the char *environ[] array).
+ */
+ free(waste);
+#endif
+ }
+#else
+ rv = setenv(name, value, 1);
+#endif
+ if (rv < 0) {
+ JS_ReportError(cx, "can't set envariable %s to %s", name, value);
+ return JS_FALSE;
+ }
+ *vp = STRING_TO_JSVAL(valstr);
+#endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */
+ return JS_TRUE;
+}
+
+static JSBool
+env_enumerate(JSContext *cx, JSObject *obj)
+{
+ static JSBool reflected;
+ char **evp, *name, *value;
+ JSString *valstr;
+ JSBool ok;
+
+ if (reflected)
+ return JS_TRUE;
+
+ for (evp = (char **)JS_GetPrivate(cx, obj); (name = *evp) != NULL; evp++) {
+ value = strchr(name, '=');
+ if (!value)
+ continue;
+ *value++ = '\0';
+ valstr = JS_NewStringCopyZ(cx, value);
+ if (!valstr) {
+ ok = JS_FALSE;
+ } else {
+ ok = JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
+ NULL, NULL, JSPROP_ENUMERATE);
+ }
+ value[-1] = '=';
+ if (!ok)
+ return JS_FALSE;
+ }
+
+ reflected = JS_TRUE;
+ return JS_TRUE;
+}
+
+static JSBool
+env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
+ JSObject **objp)
+{
+ JSString *idstr, *valstr;
+ const char *name, *value;
+
+ if (flags & JSRESOLVE_ASSIGNING)
+ return JS_TRUE;
+
+ idstr = JS_ValueToString(cx, id);
+ if (!idstr)
+ return JS_FALSE;
+ name = JS_GetStringBytes(idstr);
+ value = getenv(name);
+ if (value) {
+ valstr = JS_NewStringCopyZ(cx, value);
+ if (!valstr)
+ return JS_FALSE;
+ if (!JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return JS_FALSE;
+ }
+ *objp = obj;
+ }
+ return JS_TRUE;
+}
+
+static JSClass env_class = {
+ "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
+ JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, env_setProperty,
+ env_enumerate, (JSResolveOp) env_resolve,
+ JS_ConvertStub, JS_FinalizeStub
+};
+
+int
+main(int argc, char **argv, char **envp)
+{
+ int stackDummy;
+ JSVersion version;
+ JSRuntime *rt;
+ JSContext *cx;
+ JSObject *glob, *it, *envobj;
+ int result;
+#ifdef LIVECONNECT
+ JavaVM *java_vm = NULL;
+#endif
+#ifdef JSDEBUGGER_JAVA_UI
+ JNIEnv *java_env;
+#endif
+
+ gStackBase = (jsuword)&stackDummy;
+
+#ifdef XP_OS2
+ /* these streams are normally line buffered on OS/2 and need a \n, *
+ * so we need to unbuffer then to get a reasonable prompt */
+ setbuf(stdout,0);
+ setbuf(stderr,0);
+#endif
+
+ gErrFile = stderr;
+ gOutFile = stdout;
+
+#ifdef XP_MAC
+#ifndef XP_MAC_MPW
+ initConsole("\pJavaScript Shell", "Welcome to js shell.", &argc, &argv);
+#endif
+#endif
+
+#ifdef MAC_TEST_HACK
+/*
+ Open a file "testArgs.txt" and read each line into argc/argv.
+ Re-direct all output to "results.txt"
+*/
+ {
+ char argText[256];
+ FILE *f = fopen("testargs.txt", "r");
+ if (f) {
+ int maxArgs = 32; /* arbitrary max !!! */
+ int argText_strlen;
+ argc = 1;
+ argv = malloc(sizeof(char *) * maxArgs);
+ argv[0] = NULL;
+ while (fgets(argText, 255, f)) {
+ /* argText includes '\n' */
+ argText_strlen = strlen(argText);
+ argv[argc] = malloc(argText_strlen);
+ strncpy(argv[argc], argText, argText_strlen - 1);
+ argv[argc][argText_strlen - 1] = '\0';
+ argc++;
+ if (argc >= maxArgs)
+ break;
+ }
+ fclose(f);
+ }
+ gTestResultFile = fopen("results.txt", "w");
+ }
+
+ gErrFile = gTestResultFile;
+ gOutFile = gTestResultFile;
+#endif
+
+ version = JSVERSION_DEFAULT;
+
+ argc--;
+ argv++;
+
+ rt = JS_NewRuntime(8L * 1024L * 1024L);
+ if (!rt)
+ return 1;
+
+ cx = JS_NewContext(rt, gStackChunkSize);
+ if (!cx)
+ return 1;
+ JS_SetErrorReporter(cx, my_ErrorReporter);
+
+ glob = JS_NewObject(cx, &global_class, NULL, NULL);
+ if (!glob)
+ return 1;
+#ifdef LAZY_STANDARD_CLASSES
+ JS_SetGlobalObject(cx, glob);
+#else
+ if (!JS_InitStandardClasses(cx, glob))
+ return 1;
+#endif
+ if (!JS_DefineFunctions(cx, glob, shell_functions))
+ return 1;
+
+ /* Set version only after there is a global object. */
+ if (version != JSVERSION_DEFAULT)
+ JS_SetVersion(cx, version);
+
+ it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0);
+ if (!it)
+ return 1;
+ if (!JS_DefineProperties(cx, it, its_props))
+ return 1;
+ if (!JS_DefineFunctions(cx, it, its_methods))
+ return 1;
+
+#ifdef PERLCONNECT
+ if (!JS_InitPerlClass(cx, glob))
+ return 1;
+#endif
+
+#ifdef JSDEBUGGER
+ /*
+ * XXX A command line option to enable debugging (or not) would be good
+ */
+ _jsdc = JSD_DebuggerOnForUser(rt, NULL, NULL);
+ if (!_jsdc)
+ return 1;
+ JSD_JSContextInUse(_jsdc, cx);
+#ifdef JSD_LOWLEVEL_SOURCE
+ JS_SetSourceHandler(rt, SendSourceToJSDebugger, _jsdc);
+#endif /* JSD_LOWLEVEL_SOURCE */
+#ifdef JSDEBUGGER_JAVA_UI
+ _jsdjc = JSDJ_CreateContext();
+ if (! _jsdjc)
+ return 1;
+ JSDJ_SetJSDContext(_jsdjc, _jsdc);
+ java_env = JSDJ_CreateJavaVMAndStartDebugger(_jsdjc);
+#ifdef LIVECONNECT
+ if (java_env)
+ (*java_env)->GetJavaVM(java_env, &java_vm);
+#endif
+ /*
+ * XXX This would be the place to wait for the debugger to start.
+ * Waiting would be nice in general, but especially when a js file
+ * is passed on the cmd line.
+ */
+#endif /* JSDEBUGGER_JAVA_UI */
+#ifdef JSDEBUGGER_C_UI
+ JSDB_InitDebugger(rt, _jsdc, 0);
+#endif /* JSDEBUGGER_C_UI */
+#endif /* JSDEBUGGER */
+
+#ifdef LIVECONNECT
+ if (!JSJ_SimpleInit(cx, glob, java_vm, getenv("CLASSPATH")))
+ return 1;
+#endif
+
+ envobj = JS_DefineObject(cx, glob, "environment", &env_class, NULL, 0);
+ if (!envobj || !JS_SetPrivate(cx, envobj, envp))
+ return 1;
+
+ result = ProcessArgs(cx, glob, argv, argc);
+
+#ifdef JSDEBUGGER
+ if (_jsdc)
+ JSD_DebuggerOff(_jsdc);
+#endif /* JSDEBUGGER */
+
+#ifdef MAC_TEST_HACK
+ fclose(gTestResultFile);
+#endif
+
+ JS_DestroyContext(cx);
+ JS_DestroyRuntime(rt);
+ JS_ShutDown();
+ return result;
+}
diff --git a/src/dom/js/js.mak b/src/dom/js/js.mak
new file mode 100644
index 000000000..0f8b8f53c
--- /dev/null
+++ b/src/dom/js/js.mak
@@ -0,0 +1,4025 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+!IF "$(CFG)" == ""
+CFG=jsshell - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to jsshell - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "js - Win32 Release" && "$(CFG)" != "js - Win32 Debug" &&\
+ "$(CFG)" != "jsshell - Win32 Release" && "$(CFG)" != "jsshell - Win32 Debug" &&\
+ "$(CFG)" != "fdlibm - Win32 Release" && "$(CFG)" != "fdlibm - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "js.mak" CFG="jsshell - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "js - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "js - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "jsshell - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "jsshell - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "fdlibm - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "fdlibm - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "jsshell - Win32 Debug"
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "js___Wi1"
+# PROP BASE Intermediate_Dir "js___Wi1"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "fdlibm - Win32 Release" "$(OUTDIR)\js32.dll"
+
+CLEAN :
+ -@erase "$(INTDIR)\jsapi.obj"
+ -@erase "$(INTDIR)\jsarena.obj"
+ -@erase "$(INTDIR)\jsarray.obj"
+ -@erase "$(INTDIR)\jsatom.obj"
+ -@erase "$(INTDIR)\jsbool.obj"
+ -@erase "$(INTDIR)\jscntxt.obj"
+ -@erase "$(INTDIR)\jsdate.obj"
+ -@erase "$(INTDIR)\jsdbgapi.obj"
+ -@erase "$(INTDIR)\jsdhash.obj"
+ -@erase "$(INTDIR)\jsdtoa.obj"
+ -@erase "$(INTDIR)\jsemit.obj"
+ -@erase "$(INTDIR)\jsexn.obj"
+ -@erase "$(INTDIR)\jsfun.obj"
+ -@erase "$(INTDIR)\jsgc.obj"
+ -@erase "$(INTDIR)\jshash.obj"
+ -@erase "$(INTDIR)\jsinterp.obj"
+ -@erase "$(INTDIR)\jslock.obj"
+ -@erase "$(INTDIR)\jslog2.obj"
+ -@erase "$(INTDIR)\jslong.obj"
+ -@erase "$(INTDIR)\jsmath.obj"
+ -@erase "$(INTDIR)\jsnum.obj"
+ -@erase "$(INTDIR)\jsobj.obj"
+ -@erase "$(INTDIR)\jsopcode.obj"
+ -@erase "$(INTDIR)\jsparse.obj"
+ -@erase "$(INTDIR)\jsprf.obj"
+ -@erase "$(INTDIR)\jsregexp.obj"
+ -@erase "$(INTDIR)\jsscan.obj"
+ -@erase "$(INTDIR)\jsscope.obj"
+ -@erase "$(INTDIR)\jsscript.obj"
+ -@erase "$(INTDIR)\jsstr.obj"
+ -@erase "$(INTDIR)\jsutil.obj"
+ -@erase "$(INTDIR)\jsxdrapi.obj"
+ -@erase "$(INTDIR)\prmjtime.obj"
+ -@erase "$(OUTDIR)\js32.dll"
+ -@erase "$(OUTDIR)\js32.exp"
+ -@erase "$(OUTDIR)\js32.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /YX /c
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /D "WIN32" /D\
+ "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /Fp"$(INTDIR)/js.pch" /YX\
+ /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/js.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/js32.dll"
+# SUBTRACT LINK32 /nodefaultlib
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
+ /pdb:"$(OUTDIR)/js32.pdb" /machine:I386 /out:"$(OUTDIR)/js32.dll"\
+ /implib:"$(OUTDIR)/js32.lib" /opt:ref /opt:noicf
+LINK32_OBJS= \
+ "$(INTDIR)\jsapi.obj" \
+ "$(INTDIR)\jsarena.obj" \
+ "$(INTDIR)\jsarray.obj" \
+ "$(INTDIR)\jsatom.obj" \
+ "$(INTDIR)\jsbool.obj" \
+ "$(INTDIR)\jscntxt.obj" \
+ "$(INTDIR)\jsdate.obj" \
+ "$(INTDIR)\jsdbgapi.obj" \
+ "$(INTDIR)\jsdhash.obj" \
+ "$(INTDIR)\jsdtoa.obj" \
+ "$(INTDIR)\jsemit.obj" \
+ "$(INTDIR)\jsexn.obj" \
+ "$(INTDIR)\jsfun.obj" \
+ "$(INTDIR)\jsgc.obj" \
+ "$(INTDIR)\jshash.obj" \
+ "$(INTDIR)\jsinterp.obj" \
+ "$(INTDIR)\jslock.obj" \
+ "$(INTDIR)\jslog2.obj" \
+ "$(INTDIR)\jslong.obj" \
+ "$(INTDIR)\jsmath.obj" \
+ "$(INTDIR)\jsnum.obj" \
+ "$(INTDIR)\jsobj.obj" \
+ "$(INTDIR)\jsopcode.obj" \
+ "$(INTDIR)\jsparse.obj" \
+ "$(INTDIR)\jsprf.obj" \
+ "$(INTDIR)\jsregexp.obj" \
+ "$(INTDIR)\jsscan.obj" \
+ "$(INTDIR)\jsscope.obj" \
+ "$(INTDIR)\jsscript.obj" \
+ "$(INTDIR)\jsstr.obj" \
+ "$(INTDIR)\jsutil.obj" \
+ "$(INTDIR)\jsxdrapi.obj" \
+ "$(INTDIR)\prmjtime.obj" \
+ "$(OUTDIR)\fdlibm.lib"
+
+"$(OUTDIR)\js32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "js___Wi2"
+# PROP BASE Intermediate_Dir "js___Wi2"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "fdlibm - Win32 Debug" "$(OUTDIR)\js32.dll"
+
+CLEAN :
+ -@erase "$(INTDIR)\jsapi.obj"
+ -@erase "$(INTDIR)\jsarena.obj"
+ -@erase "$(INTDIR)\jsarray.obj"
+ -@erase "$(INTDIR)\jsatom.obj"
+ -@erase "$(INTDIR)\jsbool.obj"
+ -@erase "$(INTDIR)\jscntxt.obj"
+ -@erase "$(INTDIR)\jsdate.obj"
+ -@erase "$(INTDIR)\jsdbgapi.obj"
+ -@erase "$(INTDIR)\jsdhash.obj"
+ -@erase "$(INTDIR)\jsdtoa.obj"
+ -@erase "$(INTDIR)\jsemit.obj"
+ -@erase "$(INTDIR)\jsexn.obj"
+ -@erase "$(INTDIR)\jsfun.obj"
+ -@erase "$(INTDIR)\jsgc.obj"
+ -@erase "$(INTDIR)\jshash.obj"
+ -@erase "$(INTDIR)\jsinterp.obj"
+ -@erase "$(INTDIR)\jslock.obj"
+ -@erase "$(INTDIR)\jslog2.obj"
+ -@erase "$(INTDIR)\jslong.obj"
+ -@erase "$(INTDIR)\jsmath.obj"
+ -@erase "$(INTDIR)\jsnum.obj"
+ -@erase "$(INTDIR)\jsobj.obj"
+ -@erase "$(INTDIR)\jsopcode.obj"
+ -@erase "$(INTDIR)\jsparse.obj"
+ -@erase "$(INTDIR)\jsprf.obj"
+ -@erase "$(INTDIR)\jsregexp.obj"
+ -@erase "$(INTDIR)\jsscan.obj"
+ -@erase "$(INTDIR)\jsscope.obj"
+ -@erase "$(INTDIR)\jsscript.obj"
+ -@erase "$(INTDIR)\jsstr.obj"
+ -@erase "$(INTDIR)\jsutil.obj"
+ -@erase "$(INTDIR)\jsxdrapi.obj"
+ -@erase "$(INTDIR)\prmjtime.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
+ -@erase "$(OUTDIR)\js32.dll"
+ -@erase "$(OUTDIR)\js32.exp"
+ -@erase "$(OUTDIR)\js32.ilk"
+ -@erase "$(OUTDIR)\js32.lib"
+ -@erase "$(OUTDIR)\js32.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "DEBUG" /D _X86_=1 /D "_WINDOWS" /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "DEBUG" /D _X86_=1 /D "_WINDOWS"\
+ /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /Fp"$(INTDIR)/js.pch" /YX\
+ /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/js.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/js32.dll"
+# SUBTRACT LINK32 /nodefaultlib
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /dll /incremental:yes\
+ /pdb:"$(OUTDIR)/js32.pdb" /debug /machine:I386 /out:"$(OUTDIR)/js32.dll"\
+ /implib:"$(OUTDIR)/js32.lib"
+LINK32_OBJS= \
+ "$(INTDIR)\jsapi.obj" \
+ "$(INTDIR)\jsarena.obj" \
+ "$(INTDIR)\jsarray.obj" \
+ "$(INTDIR)\jsatom.obj" \
+ "$(INTDIR)\jsbool.obj" \
+ "$(INTDIR)\jscntxt.obj" \
+ "$(INTDIR)\jsdate.obj" \
+ "$(INTDIR)\jsdbgapi.obj" \
+ "$(INTDIR)\jsdhash.obj" \
+ "$(INTDIR)\jsdtoa.obj" \
+ "$(INTDIR)\jsemit.obj" \
+ "$(INTDIR)\jsexn.obj" \
+ "$(INTDIR)\jsfun.obj" \
+ "$(INTDIR)\jsgc.obj" \
+ "$(INTDIR)\jshash.obj" \
+ "$(INTDIR)\jsinterp.obj" \
+ "$(INTDIR)\jslock.obj" \
+ "$(INTDIR)\jslog2.obj" \
+ "$(INTDIR)\jslong.obj" \
+ "$(INTDIR)\jsmath.obj" \
+ "$(INTDIR)\jsnum.obj" \
+ "$(INTDIR)\jsobj.obj" \
+ "$(INTDIR)\jsopcode.obj" \
+ "$(INTDIR)\jsparse.obj" \
+ "$(INTDIR)\jsprf.obj" \
+ "$(INTDIR)\jsregexp.obj" \
+ "$(INTDIR)\jsscan.obj" \
+ "$(INTDIR)\jsscope.obj" \
+ "$(INTDIR)\jsscript.obj" \
+ "$(INTDIR)\jsstr.obj" \
+ "$(INTDIR)\jsutil.obj" \
+ "$(INTDIR)\jsxdrapi.obj" \
+ "$(INTDIR)\prmjtime.obj" \
+ "$(OUTDIR)\fdlibm.lib"
+
+"$(OUTDIR)\js32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "jsshell - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "jsshell\Release"
+# PROP BASE Intermediate_Dir "jsshell\Release"
+# PROP BASE Target_Dir "jsshell"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir "jsshell"
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "js - Win32 Release" "$(OUTDIR)\jsshell.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\js.obj"
+ -@erase "$(OUTDIR)\jsshell.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "XP_WIN" /D "JSFILE" /YX /c
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D\
+ "XP_WIN" /D "JSFILE" /Fp"$(INTDIR)/jsshell.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/jsshell.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:console /incremental:no\
+ /pdb:"$(OUTDIR)/jsshell.pdb" /machine:I386 /out:"$(OUTDIR)/jsshell.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\js.obj" \
+ "$(OUTDIR)\js32.lib"
+
+"$(OUTDIR)\jsshell.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "jsshell - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "jsshell\jsshell_"
+# PROP BASE Intermediate_Dir "jsshell\jsshell_"
+# PROP BASE Target_Dir "jsshell"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir "jsshell"
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "js - Win32 Debug" "$(OUTDIR)\jsshell.exe"
+
+CLEAN :
+ -@erase "$(INTDIR)\js.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
+ -@erase "$(OUTDIR)\jsshell.exe"
+ -@erase "$(OUTDIR)\jsshell.ilk"
+ -@erase "$(OUTDIR)\jsshell.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_CONSOLE" /D "_DEBUG" /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "DEBUG" /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "_CONSOLE" /D "_DEBUG" /D "WIN32"\
+ /D "XP_WIN" /D "JSFILE" /D "DEBUG" /Fp"$(INTDIR)/jsshell.pch" /YX\
+ /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/jsshell.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)/jsshell.pdb" /debug /machine:I386 /out:"$(OUTDIR)/jsshell.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\js.obj" \
+ "$(OUTDIR)\js32.lib"
+
+"$(OUTDIR)\jsshell.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "fdlibm\Release"
+# PROP BASE Intermediate_Dir "fdlibm\Release"
+# PROP BASE Target_Dir "fdlibm"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir "fdlibm"
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\fdlibm.lib"
+
+CLEAN :
+ -@erase "$(INTDIR)\e_atan2.obj"
+ -@erase "$(INTDIR)\e_pow.obj"
+ -@erase "$(INTDIR)\e_sqrt.obj"
+ -@erase "$(INTDIR)\k_standard.obj"
+ -@erase "$(INTDIR)\s_atan.obj"
+ -@erase "$(INTDIR)\s_copysign.obj"
+ -@erase "$(INTDIR)\s_fabs.obj"
+ -@erase "$(INTDIR)\s_finite.obj"
+ -@erase "$(INTDIR)\s_isnan.obj"
+ -@erase "$(INTDIR)\s_matherr.obj"
+ -@erase "$(INTDIR)\s_rint.obj"
+ -@erase "$(INTDIR)\s_scalbn.obj"
+ -@erase "$(INTDIR)\w_atan2.obj"
+ -@erase "$(INTDIR)\w_pow.obj"
+ -@erase "$(INTDIR)\w_sqrt.obj"
+ -@erase "$(OUTDIR)\fdlibm.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D "_IEEE_LIBM" /YX /c
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D\
+ "_IEEE_LIBM" /D "XP_WIN" /I .\ /Fp"$(INTDIR)/fdlibm.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/fdlibm.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)/fdlibm.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\e_atan2.obj" \
+ "$(INTDIR)\e_pow.obj" \
+ "$(INTDIR)\e_sqrt.obj" \
+ "$(INTDIR)\k_standard.obj" \
+ "$(INTDIR)\s_atan.obj" \
+ "$(INTDIR)\s_copysign.obj" \
+ "$(INTDIR)\s_fabs.obj" \
+ "$(INTDIR)\s_finite.obj" \
+ "$(INTDIR)\s_isnan.obj" \
+ "$(INTDIR)\s_matherr.obj" \
+ "$(INTDIR)\s_rint.obj" \
+ "$(INTDIR)\s_scalbn.obj" \
+ "$(INTDIR)\w_atan2.obj" \
+ "$(INTDIR)\w_pow.obj" \
+ "$(INTDIR)\w_sqrt.obj"
+
+"$(OUTDIR)\fdlibm.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "fdlibm\Debug"
+# PROP BASE Intermediate_Dir "fdlibm\Debug"
+# PROP BASE Target_Dir "fdlibm"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir "fdlibm"
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\fdlibm.lib"
+
+CLEAN :
+ -@erase "$(INTDIR)\e_atan2.obj"
+ -@erase "$(INTDIR)\e_pow.obj"
+ -@erase "$(INTDIR)\e_sqrt.obj"
+ -@erase "$(INTDIR)\k_standard.obj"
+ -@erase "$(INTDIR)\s_atan.obj"
+ -@erase "$(INTDIR)\s_copysign.obj"
+ -@erase "$(INTDIR)\s_fabs.obj"
+ -@erase "$(INTDIR)\s_finite.obj"
+ -@erase "$(INTDIR)\s_isnan.obj"
+ -@erase "$(INTDIR)\s_matherr.obj"
+ -@erase "$(INTDIR)\s_rint.obj"
+ -@erase "$(INTDIR)\s_scalbn.obj"
+ -@erase "$(INTDIR)\w_atan2.obj"
+ -@erase "$(INTDIR)\w_pow.obj"
+ -@erase "$(INTDIR)\w_sqrt.obj"
+ -@erase "$(OUTDIR)\fdlibm.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /D "_DEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D "_IEEE_LIBM" /YX /c
+CPP_PROJ=/nologo /MDd /W3 /GX /Z7 /Od /D "_DEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D\
+ "_IEEE_LIBM" /D "XP_WIN" -I .\ /Fp"$(INTDIR)/fdlibm.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/fdlibm.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)/fdlibm.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\e_atan2.obj" \
+ "$(INTDIR)\e_pow.obj" \
+ "$(INTDIR)\e_sqrt.obj" \
+ "$(INTDIR)\k_standard.obj" \
+ "$(INTDIR)\s_atan.obj" \
+ "$(INTDIR)\s_copysign.obj" \
+ "$(INTDIR)\s_fabs.obj" \
+ "$(INTDIR)\s_finite.obj" \
+ "$(INTDIR)\s_isnan.obj" \
+ "$(INTDIR)\s_matherr.obj" \
+ "$(INTDIR)\s_rint.obj" \
+ "$(INTDIR)\s_scalbn.obj" \
+ "$(INTDIR)\w_atan2.obj" \
+ "$(INTDIR)\w_pow.obj" \
+ "$(INTDIR)\w_sqrt.obj"
+
+"$(OUTDIR)\fdlibm.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+################################################################################
+# Begin Target
+
+# Name "js - Win32 Release"
+# Name "js - Win32 Debug"
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsapi.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSAPI=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdate.h"\
+ ".\jsemit.h"\
+ ".\jsexn.h"\
+ ".\jsfile.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsmath.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSAPI=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsapi.obj" : $(SOURCE) $(DEP_CPP_JSAPI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSAPI=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdate.h"\
+ ".\jsemit.h"\
+ ".\jsexn.h"\
+ ".\jsfile.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsmath.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSAPI=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsapi.obj" : $(SOURCE) $(DEP_CPP_JSAPI) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsarena.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSARE=\
+ ".\jsarena.h"\
+ ".\jsbit.h"\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsstddef.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSARE=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsarena.obj" : $(SOURCE) $(DEP_CPP_JSARE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSARE=\
+ ".\jsarena.h"\
+ ".\jsbit.h"\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsstddef.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSARE=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsarena.obj" : $(SOURCE) $(DEP_CPP_JSARE) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsarray.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSARR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSARR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsarray.obj" : $(SOURCE) $(DEP_CPP_JSARR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSARR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSARR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsarray.obj" : $(SOURCE) $(DEP_CPP_JSARR) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsatom.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSATO=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSATO=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsatom.obj" : $(SOURCE) $(DEP_CPP_JSATO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSATO=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSATO=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsatom.obj" : $(SOURCE) $(DEP_CPP_JSATO) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsbool.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSBOO=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSBOO=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsbool.obj" : $(SOURCE) $(DEP_CPP_JSBOO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSBOO=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSBOO=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsbool.obj" : $(SOURCE) $(DEP_CPP_JSBOO) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jscntxt.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSCNT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsexn.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSCNT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jscntxt.obj" : $(SOURCE) $(DEP_CPP_JSCNT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSCNT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsexn.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSCNT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jscntxt.obj" : $(SOURCE) $(DEP_CPP_JSCNT) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsdate.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSDAT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdate.h"\
+ ".\jsdtoa.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\prmjtime.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDAT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsdate.obj" : $(SOURCE) $(DEP_CPP_JSDAT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSDAT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdate.h"\
+ ".\jsdtoa.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\prmjtime.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDAT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsdate.obj" : $(SOURCE) $(DEP_CPP_JSDAT) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsdbgapi.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSDBG=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDBG=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsdbgapi.obj" : $(SOURCE) $(DEP_CPP_JSDBG) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSDBG=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDBG=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsdbgapi.obj" : $(SOURCE) $(DEP_CPP_JSDBG) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsdhash.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSDHA=\
+ ".\jsbit.h"\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jsdhash.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDHA=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsdhash.obj" : $(SOURCE) $(DEP_CPP_JSDHA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSDHA=\
+ ".\jsbit.h"\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jsdhash.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDHA=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsdhash.obj" : $(SOURCE) $(DEP_CPP_JSDHA) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsdtoa.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSDTO=\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jsdtoa.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsstddef.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDTO=\
+ ".\jsautocfg.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsdtoa.obj" : $(SOURCE) $(DEP_CPP_JSDTO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSDTO=\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jsdtoa.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsstddef.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSDTO=\
+ ".\jsautocfg.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsdtoa.obj" : $(SOURCE) $(DEP_CPP_JSDTO) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsemit.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSEMI=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSEMI=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsemit.obj" : $(SOURCE) $(DEP_CPP_JSEMI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSEMI=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSEMI=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsemit.obj" : $(SOURCE) $(DEP_CPP_JSEMI) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsexn.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSEXN=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsexn.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSEXN=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsexn.obj" : $(SOURCE) $(DEP_CPP_JSEXN) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSEXN=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsexn.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSEXN=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsexn.obj" : $(SOURCE) $(DEP_CPP_JSEXN) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsfun.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSFUN=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSFUN=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsfun.obj" : $(SOURCE) $(DEP_CPP_JSFUN) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSFUN=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSFUN=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsfun.obj" : $(SOURCE) $(DEP_CPP_JSFUN) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsgc.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSGC_=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSGC_=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsgc.obj" : $(SOURCE) $(DEP_CPP_JSGC_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSGC_=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSGC_=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsgc.obj" : $(SOURCE) $(DEP_CPP_JSGC_) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jshash.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSHAS=\
+ ".\jsbit.h"\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jshash.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSHAS=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jshash.obj" : $(SOURCE) $(DEP_CPP_JSHAS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSHAS=\
+ ".\jsbit.h"\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jshash.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSHAS=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jshash.obj" : $(SOURCE) $(DEP_CPP_JSHAS) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsinterp.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSINT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSINT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsinterp.obj" : $(SOURCE) $(DEP_CPP_JSINT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSINT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSINT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsinterp.obj" : $(SOURCE) $(DEP_CPP_JSINT) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jslock.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSLOC=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSLOC=\
+ ".\jsautocfg.h"\
+ ".\pratom.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+ ".\prthread.h"\
+
+
+"$(INTDIR)\jslock.obj" : $(SOURCE) $(DEP_CPP_JSLOC) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSLOC=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSLOC=\
+ ".\jsautocfg.h"\
+ ".\pratom.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+ ".\prthread.h"\
+
+
+"$(INTDIR)\jslock.obj" : $(SOURCE) $(DEP_CPP_JSLOC) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jslog2.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSLOG=\
+ ".\jsbit.h"\
+ ".\jscpucfg.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSLOG=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jslog2.obj" : $(SOURCE) $(DEP_CPP_JSLOG) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSLOG=\
+ ".\jsbit.h"\
+ ".\jscpucfg.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSLOG=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jslog2.obj" : $(SOURCE) $(DEP_CPP_JSLOG) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jslong.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSLON=\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSLON=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jslong.obj" : $(SOURCE) $(DEP_CPP_JSLON) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSLON=\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jstypes.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSLON=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jslong.obj" : $(SOURCE) $(DEP_CPP_JSLON) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsmath.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSMAT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslibmath.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsmath.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\prmjtime.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSMAT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsmath.obj" : $(SOURCE) $(DEP_CPP_JSMAT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSMAT=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslibmath.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsmath.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\prmjtime.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSMAT=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsmath.obj" : $(SOURCE) $(DEP_CPP_JSMAT) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsnum.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSNUM=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdtoa.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSNUM=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsnum.obj" : $(SOURCE) $(DEP_CPP_JSNUM) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSNUM=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdtoa.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSNUM=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsnum.obj" : $(SOURCE) $(DEP_CPP_JSNUM) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsobj.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSOBJ=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSOBJ=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsobj.obj" : $(SOURCE) $(DEP_CPP_JSOBJ) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSOBJ=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSOBJ=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsobj.obj" : $(SOURCE) $(DEP_CPP_JSOBJ) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsopcode.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSOPC=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsdtoa.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSOPC=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsopcode.obj" : $(SOURCE) $(DEP_CPP_JSOPC) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSOPC=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsdtoa.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSOPC=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsopcode.obj" : $(SOURCE) $(DEP_CPP_JSOPC) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsparse.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSPAR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSPAR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsparse.obj" : $(SOURCE) $(DEP_CPP_JSPAR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSPAR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSPAR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsparse.obj" : $(SOURCE) $(DEP_CPP_JSPAR) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsprf.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSPRF=\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSPRF=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsprf.obj" : $(SOURCE) $(DEP_CPP_JSPRF) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSPRF=\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSPRF=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsprf.obj" : $(SOURCE) $(DEP_CPP_JSPRF) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsregexp.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSREG=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSREG=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsregexp.obj" : $(SOURCE) $(DEP_CPP_JSREG) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSREG=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSREG=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsregexp.obj" : $(SOURCE) $(DEP_CPP_JSREG) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsscan.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSSCA=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdtoa.h"\
+ ".\jsexn.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSCA=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsscan.obj" : $(SOURCE) $(DEP_CPP_JSSCA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSSCA=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdtoa.h"\
+ ".\jsexn.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSCA=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsscan.obj" : $(SOURCE) $(DEP_CPP_JSSCA) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsscope.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSSCO=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSCO=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsscope.obj" : $(SOURCE) $(DEP_CPP_JSSCO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSSCO=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSCO=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsscope.obj" : $(SOURCE) $(DEP_CPP_JSSCO) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsscript.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSSCR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSCR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsscript.obj" : $(SOURCE) $(DEP_CPP_JSSCR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSSCR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSCR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsscript.obj" : $(SOURCE) $(DEP_CPP_JSSCR) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsstr.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSSTR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSTR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsstr.obj" : $(SOURCE) $(DEP_CPP_JSSTR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSSTR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsarray.h"\
+ ".\jsatom.h"\
+ ".\jsbool.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsnum.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSSTR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsstr.obj" : $(SOURCE) $(DEP_CPP_JSSTR) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsutil.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSUTI=\
+ ".\jscpucfg.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSUTI=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsutil.obj" : $(SOURCE) $(DEP_CPP_JSUTI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSUTI=\
+ ".\jscpucfg.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSUTI=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\jsutil.obj" : $(SOURCE) $(DEP_CPP_JSUTI) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\jsxdrapi.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_JSXDR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSXDR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsxdrapi.obj" : $(SOURCE) $(DEP_CPP_JSXDR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_JSXDR=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscope.h"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ ".\jsxdrapi.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JSXDR=\
+ ".\jsautocfg.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\jsxdrapi.obj" : $(SOURCE) $(DEP_CPP_JSXDR) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\prmjtime.c
+
+!IF "$(CFG)" == "js - Win32 Release"
+
+DEP_CPP_PRMJT=\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jstypes.h"\
+ ".\prmjtime.h"\
+ {$(INCLUDE)}"\sys\TIMEB.H"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_PRMJT=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\prmjtime.obj" : $(SOURCE) $(DEP_CPP_PRMJT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "js - Win32 Debug"
+
+DEP_CPP_PRMJT=\
+ ".\jscompat.h"\
+ ".\jscpucfg.h"\
+ ".\jslong.h"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsprf.h"\
+ ".\jstypes.h"\
+ ".\prmjtime.h"\
+ {$(INCLUDE)}"\sys\TIMEB.H"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_PRMJT=\
+ ".\jsautocfg.h"\
+
+
+"$(INTDIR)\prmjtime.obj" : $(SOURCE) $(DEP_CPP_PRMJT) "$(INTDIR)"
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Project Dependency
+
+# Project_Dep_Name "fdlibm"
+
+!IF "$(CFG)" == "js - Win32 Debug"
+
+"fdlibm - Win32 Debug" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="fdlibm - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "js - Win32 Release"
+
+"fdlibm - Win32 Release" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="fdlibm - Win32 Release"
+
+!ENDIF
+
+# End Project Dependency
+# End Target
+################################################################################
+# Begin Target
+
+# Name "jsshell - Win32 Release"
+# Name "jsshell - Win32 Debug"
+
+!IF "$(CFG)" == "jsshell - Win32 Release"
+
+!ELSEIF "$(CFG)" == "jsshell - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\js.c
+DEP_CPP_JS_C42=\
+ ".\js.msg"\
+ ".\jsapi.h"\
+ ".\jsarena.h"\
+ ".\jsatom.h"\
+ ".\jsclist.h"\
+ ".\jscntxt.h"\
+ ".\jscompat.h"\
+ ".\jsconfig.h"\
+ ".\jscpucfg.h"\
+ ".\jsdbgapi.h"\
+ ".\jsemit.h"\
+ ".\jsfun.h"\
+ ".\jsgc.h"\
+ ".\jshash.h"\
+ ".\jsinterp.h"\
+ ".\jslock.h"\
+ ".\jslong.h"\
+ ".\jsobj.h"\
+ ".\jsopcode.h"\
+ ".\jsopcode.tbl"\
+ ".\jsosdep.h"\
+ ".\jsotypes.h"\
+ ".\jsparse.h"\
+ ".\jsprf.h"\
+ ".\jsprvtd.h"\
+ ".\jspubtd.h"\
+ ".\jsregexp.h"\
+ ".\jsscan.h"\
+ ".\jsscope.h"\
+ ".\jsscript.h"\
+ ".\jsshell.msg"\
+ ".\jsstddef.h"\
+ ".\jsstr.h"\
+ ".\jstypes.h"\
+ ".\jsutil.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+NODEP_CPP_JS_C42=\
+ ".\jsautocfg.h"\
+ ".\jsdb.h"\
+ ".\jsdebug.h"\
+ ".\jsdjava.h"\
+ ".\jsjava.h"\
+ ".\jsperl.h"\
+ ".\prcvar.h"\
+ ".\prlock.h"\
+
+
+"$(INTDIR)\js.obj" : $(SOURCE) $(DEP_CPP_JS_C42) "$(INTDIR)"
+
+
+# End Source File
+################################################################################
+# Begin Project Dependency
+
+# Project_Dep_Name "js"
+
+!IF "$(CFG)" == "jsshell - Win32 Release"
+
+"js - Win32 Release" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="js - Win32 Release"
+
+!ELSEIF "$(CFG)" == "jsshell - Win32 Debug"
+
+"js - Win32 Debug" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="js - Win32 Debug"
+
+!ENDIF
+
+# End Project Dependency
+# End Target
+################################################################################
+# Begin Target
+
+# Name "fdlibm - Win32 Release"
+# Name "fdlibm - Win32 Debug"
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\w_atan2.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_W_ATA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\w_atan2.obj" : $(SOURCE) $(DEP_CPP_W_ATA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_W_ATA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\w_atan2.obj" : $(SOURCE) $(DEP_CPP_W_ATA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_copysign.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_COP=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_copysign.obj" : $(SOURCE) $(DEP_CPP_S_COP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_COP=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_copysign.obj" : $(SOURCE) $(DEP_CPP_S_COP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\w_pow.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_W_POW=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\w_pow.obj" : $(SOURCE) $(DEP_CPP_W_POW) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_W_POW=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\w_pow.obj" : $(SOURCE) $(DEP_CPP_W_POW) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\e_pow.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_E_POW=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\e_pow.obj" : $(SOURCE) $(DEP_CPP_E_POW) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_E_POW=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\e_pow.obj" : $(SOURCE) $(DEP_CPP_E_POW) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\k_standard.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_K_STA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\k_standard.obj" : $(SOURCE) $(DEP_CPP_K_STA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_K_STA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\k_standard.obj" : $(SOURCE) $(DEP_CPP_K_STA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\e_atan2.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_E_ATA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\e_atan2.obj" : $(SOURCE) $(DEP_CPP_E_ATA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_E_ATA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\e_atan2.obj" : $(SOURCE) $(DEP_CPP_E_ATA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_isnan.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_ISN=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_isnan.obj" : $(SOURCE) $(DEP_CPP_S_ISN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_ISN=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_isnan.obj" : $(SOURCE) $(DEP_CPP_S_ISN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_fabs.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_FAB=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_fabs.obj" : $(SOURCE) $(DEP_CPP_S_FAB) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_FAB=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_fabs.obj" : $(SOURCE) $(DEP_CPP_S_FAB) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\w_sqrt.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_W_SQR=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\w_sqrt.obj" : $(SOURCE) $(DEP_CPP_W_SQR) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_W_SQR=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\w_sqrt.obj" : $(SOURCE) $(DEP_CPP_W_SQR) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_scalbn.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_SCA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_scalbn.obj" : $(SOURCE) $(DEP_CPP_S_SCA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_SCA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_scalbn.obj" : $(SOURCE) $(DEP_CPP_S_SCA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\e_sqrt.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_E_SQR=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\e_sqrt.obj" : $(SOURCE) $(DEP_CPP_E_SQR) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_E_SQR=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\e_sqrt.obj" : $(SOURCE) $(DEP_CPP_E_SQR) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_rint.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_RIN=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_rint.obj" : $(SOURCE) $(DEP_CPP_S_RIN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_RIN=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_rint.obj" : $(SOURCE) $(DEP_CPP_S_RIN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_atan.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_ATA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_atan.obj" : $(SOURCE) $(DEP_CPP_S_ATA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_ATA=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_atan.obj" : $(SOURCE) $(DEP_CPP_S_ATA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_finite.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_FIN=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_finite.obj" : $(SOURCE) $(DEP_CPP_S_FIN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_FIN=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_finite.obj" : $(SOURCE) $(DEP_CPP_S_FIN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fdlibm\s_matherr.c
+
+!IF "$(CFG)" == "fdlibm - Win32 Release"
+
+DEP_CPP_S_MAT=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_matherr.obj" : $(SOURCE) $(DEP_CPP_S_MAT) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fdlibm - Win32 Debug"
+
+DEP_CPP_S_MAT=\
+ ".\fdlibm\fdlibm.h"\
+
+
+"$(INTDIR)\s_matherr.obj" : $(SOURCE) $(DEP_CPP_S_MAT) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/src/dom/js/js.msg b/src/dom/js/js.msg
new file mode 100644
index 000000000..dbc571fdf
--- /dev/null
+++ b/src/dom/js/js.msg
@@ -0,0 +1,251 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * This is the JavaScript error message file.
+ *
+ * The format for each JS error message is:
+ *
+ * MSG_DEF(<SYMBOLIC_NAME>, <ERROR_NUMBER>, <ARGUMENT_COUNT>, <EXCEPTION_NAME>,
+ * <FORMAT_STRING>)
+ *
+ * where ;
+ * <SYMBOLIC_NAME> is a legal C identifer that will be used in the
+ * JS engine source.
+ *
+ * <ERROR_NUMBER> is an unique integral value identifying this error.
+ *
+ * <ARGUMENT_COUNT> is an integer literal specifying the total number of
+ * replaceable arguments in the following format string.
+ *
+ * <EXCEPTION_NAME> is an exception index from the enum in jsexn.c;
+ * JSEXN_NONE for none. The given exception index will be raised by the
+ * engine when the corresponding error occurs.
+ *
+ * <FORMAT_STRING> is a string literal, optionally containing sequences
+ * {X} where X is an integer representing the argument number that will
+ * be replaced with a string value when the error is reported.
+ *
+ * e.g.
+ *
+ * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 73, JSEXN_NONE, 2,
+ * "{0} is not a member of the {1} family")
+ *
+ * can be used:
+ *
+ * JS_ReportErrorNumber(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey");
+ *
+ * to report:
+ *
+ * "Rhino is not a member of the Monkey family"
+ *
+ * Before adding a new MSG_DEF at the end, look for JSMSG_UNUSED<n> free
+ * index placeholders in the middle of the list.
+ */
+
+MSG_DEF(JSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "<Error #0 is reserved>")
+MSG_DEF(JSMSG_NOT_DEFINED, 1, 1, JSEXN_REFERENCEERR, "{0} is not defined")
+MSG_DEF(JSMSG_NO_REG_EXPS, 2, 1, JSEXN_INTERNALERR, "sorry, regular expression are not supported")
+MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, 3, JSEXN_NONE, "{0} requires more than {1} argument{2}")
+MSG_DEF(JSMSG_BAD_CHAR, 4, 1, JSEXN_NONE, "invalid format character {0}")
+MSG_DEF(JSMSG_BAD_TYPE, 5, 1, JSEXN_NONE, "unknown type {0}")
+MSG_DEF(JSMSG_CANT_LOCK, 6, 0, JSEXN_NONE, "can't lock memory")
+MSG_DEF(JSMSG_CANT_UNLOCK, 7, 0, JSEXN_NONE, "can't unlock memory")
+MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
+MSG_DEF(JSMSG_NO_CONSTRUCTOR, 9, 1, JSEXN_NONE, "{0} has no constructor")
+MSG_DEF(JSMSG_CANT_ALIAS, 10, 3, JSEXN_NONE, "can't alias {0} to {1} in class {2}")
+MSG_DEF(JSMSG_UNUSED11, 11, 0, JSEXN_NONE, "<Error #11 is currently unused>")
+MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
+MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER, 13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}")
+MSG_DEF(JSMSG_TOO_MANY_LITERALS, 14, 0, JSEXN_INTERNALERR, "too many literals")
+MSG_DEF(JSMSG_CANT_WATCH, 15, 1, JSEXN_NONE, "can't watch non-native objects of class {0}")
+MSG_DEF(JSMSG_STACK_UNDERFLOW, 16, 2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}")
+MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_INTERNALERR, "{0} too large")
+MSG_DEF(JSMSG_UNUSED18, 18, 0, JSEXN_NONE, "<Error #18 is currently unused>")
+MSG_DEF(JSMSG_READ_ONLY, 19, 1, JSEXN_ERR, "{0} is read-only")
+MSG_DEF(JSMSG_BAD_FORMAL, 20, 0, JSEXN_SYNTAXERR, "malformed formal parameter")
+MSG_DEF(JSMSG_SAME_FORMAL, 21, 1, JSEXN_NONE, "duplicate formal argument {0}")
+MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_TYPEERR, "{0} is not a function")
+MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_TYPEERR, "{0} is not a constructor")
+MSG_DEF(JSMSG_STACK_OVERFLOW, 24, 1, JSEXN_INTERNALERR, "stack overflow in {0}")
+MSG_DEF(JSMSG_NOT_EXPORTED, 25, 1, JSEXN_NONE, "{0} is not exported")
+MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_INTERNALERR, "too much recursion")
+MSG_DEF(JSMSG_IN_NOT_OBJECT, 27, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
+MSG_DEF(JSMSG_BAD_NEW_RESULT, 28, 1, JSEXN_NONE, "invalid new expression result {0}")
+MSG_DEF(JSMSG_BAD_SHARP_DEF, 29, 1, JSEXN_ERR, "invalid sharp variable definition #{0}=")
+MSG_DEF(JSMSG_BAD_SHARP_USE, 30, 1, JSEXN_ERR, "invalid sharp variable use #{0}#")
+MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
+MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
+MSG_DEF(JSMSG_BAD_RADIX, 33, 1, JSEXN_ERR, "illegal radix {0}")
+MSG_DEF(JSMSG_NAN, 34, 1, JSEXN_ERR, "{0} is not a number")
+MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_NONE, "can't convert {0} to an integer")
+MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_ERR, "cyclic {0} value")
+MSG_DEF(JSMSG_PERMANENT, 37, 1, JSEXN_ERR, "{0} is permanent")
+MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
+MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TYPEERR, "{0} has no properties")
+MSG_DEF(JSMSG_CANT_FIND_CLASS, 40, 1, JSEXN_NONE, "can't find class id {0}")
+MSG_DEF(JSMSG_CANT_XDR_CLASS, 41, 1, JSEXN_NONE, "can't XDR class {0}")
+MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 42, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})")
+MSG_DEF(JSMSG_UNKNOWN_FORMAT, 43, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}")
+MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 44, 0, JSEXN_SYNTAXERR, "too many constructor arguments")
+MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 45, 0, JSEXN_SYNTAXERR, "too many function arguments")
+MSG_DEF(JSMSG_BAD_QUANTIFIER, 46, 1, JSEXN_SYNTAXERR, "invalid quantifier {0}")
+MSG_DEF(JSMSG_MIN_TOO_BIG, 47, 1, JSEXN_SYNTAXERR, "overlarge minimum {0}")
+MSG_DEF(JSMSG_MAX_TOO_BIG, 48, 1, JSEXN_SYNTAXERR, "overlarge maximum {0}")
+MSG_DEF(JSMSG_OUT_OF_ORDER, 49, 1, JSEXN_SYNTAXERR, "maximum {0} less than minimum")
+MSG_DEF(JSMSG_ZERO_QUANTIFIER, 50, 1, JSEXN_SYNTAXERR, "zero quantifier {0}")
+MSG_DEF(JSMSG_UNTERM_QUANTIFIER, 51, 1, JSEXN_SYNTAXERR, "unterminated quantifier {0}")
+MSG_DEF(JSMSG_EMPTY_BEFORE_STAR, 52, 0, JSEXN_SYNTAXERR, "regular expression before * could be empty")
+MSG_DEF(JSMSG_EMPTY_BEFORE_PLUS, 53, 0, JSEXN_SYNTAXERR, "regular expression before + could be empty")
+MSG_DEF(JSMSG_MISSING_PAREN, 54, 0, JSEXN_SYNTAXERR, "unterminated parenthetical")
+MSG_DEF(JSMSG_UNTERM_CLASS, 55, 1, JSEXN_SYNTAXERR, "unterminated character class {0}")
+MSG_DEF(JSMSG_TRAILING_SLASH, 56, 0, JSEXN_SYNTAXERR, "trailing \\ in regular expression")
+MSG_DEF(JSMSG_BAD_CLASS_RANGE, 57, 0, JSEXN_SYNTAXERR, "invalid range in character class")
+MSG_DEF(JSMSG_BAD_FLAG, 58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
+MSG_DEF(JSMSG_NO_INPUT, 59, 3, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}")
+MSG_DEF(JSMSG_CANT_OPEN, 60, 2, JSEXN_NONE, "can't open {0}: {1}")
+MSG_DEF(JSMSG_BAD_STRING_MASK, 61, 1, JSEXN_ERR, "invalid string escape mask {0}")
+MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
+MSG_DEF(JSMSG_END_OF_DATA, 63, 0, JSEXN_NONE, "unexpected end of data")
+MSG_DEF(JSMSG_SEEK_BEYOND_START, 64, 0, JSEXN_NONE, "illegal seek beyond start")
+MSG_DEF(JSMSG_SEEK_BEYOND_END, 65, 0, JSEXN_NONE, "illegal seek beyond end")
+MSG_DEF(JSMSG_END_SEEK, 66, 0, JSEXN_NONE, "illegal end-based seek")
+MSG_DEF(JSMSG_WHITHER_WHENCE, 67, 1, JSEXN_NONE, "unknown seek whence: {0}")
+MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 68, 0, JSEXN_NONE, "bad script XDR magic number")
+MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
+MSG_DEF(JSMSG_MISSING_FORMAL, 70, 0, JSEXN_SYNTAXERR, "missing formal parameter")
+MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
+MSG_DEF(JSMSG_CURLY_BEFORE_BODY, 72, 0, JSEXN_SYNTAXERR, "missing { before function body")
+MSG_DEF(JSMSG_CURLY_AFTER_BODY, 73, 0, JSEXN_SYNTAXERR, "missing } after function body")
+MSG_DEF(JSMSG_PAREN_BEFORE_COND, 74, 0, JSEXN_SYNTAXERR, "missing ( before condition")
+MSG_DEF(JSMSG_PAREN_AFTER_COND, 75, 0, JSEXN_SYNTAXERR, "missing ) after condition")
+MSG_DEF(JSMSG_NO_IMPORT_NAME, 76, 0, JSEXN_SYNTAXERR, "missing name in import statement")
+MSG_DEF(JSMSG_NAME_AFTER_DOT, 77, 0, JSEXN_SYNTAXERR, "missing name after . operator")
+MSG_DEF(JSMSG_BRACKET_IN_INDEX, 78, 0, JSEXN_SYNTAXERR, "missing ] in index expression")
+MSG_DEF(JSMSG_NO_EXPORT_NAME, 79, 0, JSEXN_SYNTAXERR, "missing name in export statement")
+MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 80, 0, JSEXN_SYNTAXERR, "missing ( before switch expression")
+MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 81, 0, JSEXN_SYNTAXERR, "missing ) after switch expression")
+MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 82, 0, JSEXN_SYNTAXERR, "missing { before switch body")
+MSG_DEF(JSMSG_COLON_AFTER_CASE, 83, 0, JSEXN_SYNTAXERR, "missing : after case label")
+MSG_DEF(JSMSG_WHILE_AFTER_DO, 84, 0, JSEXN_SYNTAXERR, "missing while after do-loop body")
+MSG_DEF(JSMSG_PAREN_AFTER_FOR, 85, 0, JSEXN_SYNTAXERR, "missing ( after for")
+MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 86, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
+MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 87, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition")
+MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL, 88, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control")
+MSG_DEF(JSMSG_CURLY_BEFORE_TRY, 89, 0, JSEXN_SYNTAXERR, "missing { before try block")
+MSG_DEF(JSMSG_CURLY_AFTER_TRY, 90, 0, JSEXN_SYNTAXERR, "missing } after try block")
+MSG_DEF(JSMSG_PAREN_BEFORE_CATCH, 91, 0, JSEXN_SYNTAXERR, "missing ( before catch")
+MSG_DEF(JSMSG_CATCH_IDENTIFIER, 92, 0, JSEXN_SYNTAXERR, "missing identifier in catch")
+MSG_DEF(JSMSG_PAREN_AFTER_CATCH, 93, 0, JSEXN_SYNTAXERR, "missing ) after catch")
+MSG_DEF(JSMSG_CURLY_BEFORE_CATCH, 94, 0, JSEXN_SYNTAXERR, "missing { before catch block")
+MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 95, 0, JSEXN_SYNTAXERR, "missing } after catch block")
+MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY, 96, 0, JSEXN_SYNTAXERR, "missing { before finally block")
+MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 97, 0, JSEXN_SYNTAXERR, "missing } after finally block")
+MSG_DEF(JSMSG_CATCH_OR_FINALLY, 98, 0, JSEXN_SYNTAXERR, "missing catch or finally after try")
+MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 99, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object")
+MSG_DEF(JSMSG_PAREN_AFTER_WITH, 100, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object")
+MSG_DEF(JSMSG_CURLY_IN_COMPOUND, 101, 0, JSEXN_SYNTAXERR, "missing } in compound statement")
+MSG_DEF(JSMSG_NO_VARIABLE_NAME, 102, 0, JSEXN_SYNTAXERR, "missing variable name")
+MSG_DEF(JSMSG_COLON_IN_COND, 103, 0, JSEXN_SYNTAXERR, "missing : in conditional expression")
+MSG_DEF(JSMSG_PAREN_AFTER_ARGS, 104, 0, JSEXN_SYNTAXERR, "missing ) after argument list")
+MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 105, 0, JSEXN_SYNTAXERR, "missing ] after element list")
+MSG_DEF(JSMSG_COLON_AFTER_ID, 106, 0, JSEXN_SYNTAXERR, "missing : after property id")
+MSG_DEF(JSMSG_CURLY_AFTER_LIST, 107, 0, JSEXN_SYNTAXERR, "missing } after property list")
+MSG_DEF(JSMSG_PAREN_IN_PAREN, 108, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
+MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 109, 0, JSEXN_SYNTAXERR, "missing ; before statement")
+MSG_DEF(JSMSG_NO_RETURN_VALUE, 110, 1, JSEXN_TYPEERR, "function {0} does not always return a value")
+MSG_DEF(JSMSG_DUPLICATE_FORMAL, 111, 1, JSEXN_TYPEERR, "duplicate formal argument {0}")
+MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 112, 1, JSEXN_NONE, "test for equality (==) mistyped as assignment (=)?{0}")
+MSG_DEF(JSMSG_BAD_IMPORT, 113, 0, JSEXN_SYNTAXERR, "invalid import expression")
+MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 114, 0, JSEXN_SYNTAXERR, "more than one switch default")
+MSG_DEF(JSMSG_TOO_MANY_CASES, 115, 0, JSEXN_INTERNALERR, "too many switch cases")
+MSG_DEF(JSMSG_BAD_SWITCH, 116, 0, JSEXN_SYNTAXERR, "invalid switch statement")
+MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 117, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side")
+MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 118, 0, JSEXN_SYNTAXERR, "catch after unconditional catch")
+MSG_DEF(JSMSG_CATCH_WITHOUT_TRY, 119, 0, JSEXN_SYNTAXERR, "catch without try")
+MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 120, 0, JSEXN_SYNTAXERR, "finally without try")
+MSG_DEF(JSMSG_LABEL_NOT_FOUND, 121, 0, JSEXN_SYNTAXERR, "label not found")
+MSG_DEF(JSMSG_TOUGH_BREAK, 122, 0, JSEXN_SYNTAXERR, "invalid break")
+MSG_DEF(JSMSG_BAD_CONTINUE, 123, 0, JSEXN_SYNTAXERR, "invalid continue")
+MSG_DEF(JSMSG_BAD_RETURN, 124, 0, JSEXN_SYNTAXERR, "invalid return")
+MSG_DEF(JSMSG_BAD_LABEL, 125, 0, JSEXN_SYNTAXERR, "invalid label")
+MSG_DEF(JSMSG_DUPLICATE_LABEL, 126, 0, JSEXN_SYNTAXERR, "duplicate label")
+MSG_DEF(JSMSG_VAR_HIDES_ARG, 127, 1, JSEXN_TYPEERR, "variable {0} hides argument")
+MSG_DEF(JSMSG_BAD_VAR_INIT, 128, 0, JSEXN_SYNTAXERR, "invalid variable initialization")
+MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 129, 0, JSEXN_SYNTAXERR, "invalid assignment left-hand side")
+MSG_DEF(JSMSG_BAD_OPERAND, 130, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
+MSG_DEF(JSMSG_BAD_PROP_ID, 131, 0, JSEXN_SYNTAXERR, "invalid property id")
+MSG_DEF(JSMSG_RESERVED_ID, 132, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
+MSG_DEF(JSMSG_SYNTAX_ERROR, 133, 0, JSEXN_SYNTAXERR, "syntax error")
+MSG_DEF(JSMSG_BAD_SHARP_VAR_DEF, 134, 0, JSEXN_SYNTAXERR, "invalid sharp variable definition")
+MSG_DEF(JSMSG_BAD_PROTOTYPE, 135, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object")
+MSG_DEF(JSMSG_MISSING_EXPONENT, 136, 0, JSEXN_SYNTAXERR, "missing exponent")
+MSG_DEF(JSMSG_OUT_OF_MEMORY, 137, 0, JSEXN_ERR, "out of memory")
+MSG_DEF(JSMSG_UNTERMINATED_STRING, 138, 0, JSEXN_SYNTAXERR, "unterminated string literal")
+MSG_DEF(JSMSG_TOO_MANY_PARENS, 139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
+MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 140, 0, JSEXN_SYNTAXERR, "unterminated comment")
+MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
+MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 142, 0, JSEXN_SYNTAXERR, "invalid flag after regular expression")
+MSG_DEF(JSMSG_SHARPVAR_TOO_BIG, 143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number")
+MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character")
+MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_NONE, "{0} is not a legal ECMA-262 octal constant")
+MSG_DEF(JSMSG_BAD_INDIRECT_CALL, 146, 1, JSEXN_EVALERR, "function {0} must be called directly, and not by way of a function of another name.")
+MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 147, 1, JSEXN_NONE, "uncaught exception: {0}")
+MSG_DEF(JSMSG_INVALID_BACKREF, 148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference")
+MSG_DEF(JSMSG_BAD_BACKREF, 149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses")
+MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out of range")
+MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_SYNTAXERR, "invalid {0} usage")
+MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 152, 0, JSEXN_RANGEERR, "invalid array length")
+MSG_DEF(JSMSG_CANT_DESCRIBE_PROPS, 153, 1, JSEXN_NONE, "can't describe non-native properties of class {0}")
+MSG_DEF(JSMSG_BAD_APPLY_ARGS, 154, 0, JSEXN_TYPEERR, "second argument to Function.prototype.apply must be an array")
+MSG_DEF(JSMSG_REDECLARED_VAR, 155, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}")
+MSG_DEF(JSMSG_UNDECLARED_VAR, 156, 1, JSEXN_TYPEERR, "assignment to undeclared variable {0}")
+MSG_DEF(JSMSG_ANON_NO_RETURN_VALUE, 157, 0, JSEXN_TYPEERR, "anonymous function does not always return a value")
+MSG_DEF(JSMSG_DEPRECATED_USAGE, 158, 1, JSEXN_REFERENCEERR, "deprecated {0} usage")
+MSG_DEF(JSMSG_BAD_URI, 159, 0, JSEXN_URIERR, "malformed URI sequence")
+MSG_DEF(JSMSG_GETTER_ONLY, 160, 0, JSEXN_TYPEERR, "setting a property that has only a getter")
+MSG_DEF(JSMSG_TRAILING_COMMA, 161, 0, JSEXN_SYNTAXERR, "trailing comma is not legal in ECMA-262 object initializers")
+MSG_DEF(JSMSG_UNDEFINED_PROP, 162, 1, JSEXN_TYPEERR, "reference to undefined property {0}")
+MSG_DEF(JSMSG_USELESS_EXPR, 163, 0, JSEXN_TYPEERR, "useless expression")
+MSG_DEF(JSMSG_REDECLARED_PARAM, 164, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
+MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 165, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
+MSG_DEF(JSMSG_RESERVED_SLOT_RANGE, 166, 0, JSEXN_RANGEERR, "reserved slot index out of range")
+MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode JSPrincipals")
+MSG_DEF(JSMSG_CANT_SEAL_OBJECT, 168, 1, JSEXN_ERR, "can't seal {0} objects")
+MSG_DEF(JSMSG_CANT_UNSEAL_OBJECT, 169, 1, JSEXN_ERR, "can't unseal {0} objects")
diff --git a/src/dom/js/jsapi.c b/src/dom/js/jsapi.c
new file mode 100644
index 000000000..faf02d983
--- /dev/null
+++ b/src/dom/js/jsapi.c
@@ -0,0 +1,4187 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JavaScript API.
+ */
+#include "jsstddef.h"
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsclist.h"
+#include "jsdhash.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdate.h"
+#include "jsdtoa.h"
+#include "jsemit.h"
+#include "jsexn.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsmath.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsparse.h"
+#include "jsregexp.h"
+#include "jsscan.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+#include "prmjtime.h"
+
+#if JS_HAS_FILE_OBJECT
+#include "jsfile.h"
+#endif
+
+#ifdef HAVE_VA_LIST_AS_ARRAY
+#define JS_ADDRESSOF_VA_LIST(ap) (ap)
+#else
+#define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
+#endif
+
+#if defined(JS_PARANOID_REQUEST) && defined(JS_THREADSAFE)
+#define CHECK_REQUEST(cx) JS_ASSERT(cx->requestDepth)
+#else
+#define CHECK_REQUEST(cx) ((void)0)
+#endif
+
+JS_PUBLIC_API(int64)
+JS_Now()
+{
+ return PRMJ_Now();
+}
+
+JS_PUBLIC_API(jsval)
+JS_GetNaNValue(JSContext *cx)
+{
+ return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+}
+
+JS_PUBLIC_API(jsval)
+JS_GetNegativeInfinityValue(JSContext *cx)
+{
+ return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
+}
+
+JS_PUBLIC_API(jsval)
+JS_GetPositiveInfinityValue(JSContext *cx)
+{
+ return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
+}
+
+JS_PUBLIC_API(jsval)
+JS_GetEmptyStringValue(JSContext *cx)
+{
+ return STRING_TO_JSVAL(cx->runtime->emptyString);
+}
+
+static JSBool
+TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
+ jsval **vpp, va_list *app)
+{
+ const char *format;
+ JSArgumentFormatMap *map;
+
+ format = *formatp;
+ for (map = cx->argumentFormatMap; map; map = map->next) {
+ if (!strncmp(format, map->format, map->length)) {
+ *formatp = format + map->length;
+ return map->formatter(cx, format, fromJS, vpp, app);
+ }
+ }
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
+ return JS_FALSE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
+ ...)
+{
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, format);
+ ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
+ va_end(ap);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
+ const char *format, va_list ap)
+{
+ jsval *sp;
+ JSBool required;
+ char c;
+ JSFunction *fun;
+ jsdouble d;
+ JSString *str;
+ JSObject *obj;
+
+ CHECK_REQUEST(cx);
+ sp = argv;
+ required = JS_TRUE;
+ while ((c = *format++) != '\0') {
+ if (isspace(c))
+ continue;
+ if (c == '/') {
+ required = JS_FALSE;
+ continue;
+ }
+ if (sp == argv + argc) {
+ if (required) {
+ fun = js_ValueToFunction(cx, &argv[-2], 0);
+ if (fun) {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_MORE_ARGS_NEEDED,
+ JS_GetFunctionName(fun), numBuf,
+ (argc == 1) ? "" : "s");
+ }
+ return JS_FALSE;
+ }
+ break;
+ }
+ switch (c) {
+ case 'b':
+ if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
+ return JS_FALSE;
+ break;
+ case 'c':
+ if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
+ return JS_FALSE;
+ break;
+ case 'i':
+ if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
+ return JS_FALSE;
+ break;
+ case 'u':
+ if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
+ return JS_FALSE;
+ break;
+ case 'j':
+ if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
+ return JS_FALSE;
+ break;
+ case 'd':
+ if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
+ return JS_FALSE;
+ break;
+ case 'I':
+ if (!js_ValueToNumber(cx, *sp, &d))
+ return JS_FALSE;
+ *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
+ break;
+ case 's':
+ case 'S':
+ case 'W':
+ str = js_ValueToString(cx, *sp);
+ if (!str)
+ return JS_FALSE;
+ *sp = STRING_TO_JSVAL(str);
+ if (c == 's')
+ *va_arg(ap, char **) = JS_GetStringBytes(str);
+ else if (c == 'W')
+ *va_arg(ap, jschar **) = JS_GetStringChars(str);
+ else
+ *va_arg(ap, JSString **) = str;
+ break;
+ case 'o':
+ if (!js_ValueToObject(cx, *sp, &obj))
+ return JS_FALSE;
+ *sp = OBJECT_TO_JSVAL(obj);
+ *va_arg(ap, JSObject **) = obj;
+ break;
+ case 'f':
+ fun = js_ValueToFunction(cx, sp, 0);
+ if (!fun)
+ return JS_FALSE;
+ *sp = OBJECT_TO_JSVAL(fun->object);
+ *va_arg(ap, JSFunction **) = fun;
+ break;
+ case 'v':
+ *va_arg(ap, jsval *) = *sp;
+ break;
+ case '*':
+ break;
+ default:
+ format--;
+ if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
+ JS_ADDRESSOF_VA_LIST(ap))) {
+ return JS_FALSE;
+ }
+ /* NB: the formatter already updated sp, so we continue here. */
+ continue;
+ }
+ sp++;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(jsval *)
+JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
+{
+ va_list ap;
+ jsval *argv;
+
+ va_start(ap, format);
+ argv = JS_PushArgumentsVA(cx, markp, format, ap);
+ va_end(ap);
+ return argv;
+}
+
+JS_PUBLIC_API(jsval *)
+JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
+{
+ uintN argc;
+ jsval *argv, *sp;
+ char c;
+ const char *cp;
+ JSString *str;
+ JSFunction *fun;
+ JSStackHeader *sh;
+
+ CHECK_REQUEST(cx);
+ *markp = NULL;
+ argc = 0;
+ for (cp = format; (c = *cp) != '\0'; cp++) {
+ /*
+ * Count non-space non-star characters as individual jsval arguments.
+ * This may over-allocate stack, but we'll fix below.
+ */
+ if (isspace(c) || c == '*')
+ continue;
+ argc++;
+ }
+ sp = js_AllocStack(cx, argc, markp);
+ if (!sp)
+ return NULL;
+ argv = sp;
+ while ((c = *format++) != '\0') {
+ if (isspace(c) || c == '*')
+ continue;
+ switch (c) {
+ case 'b':
+ *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
+ break;
+ case 'c':
+ *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
+ break;
+ case 'i':
+ case 'j':
+ if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
+ goto bad;
+ break;
+ case 'u':
+ if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
+ goto bad;
+ break;
+ case 'd':
+ case 'I':
+ if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
+ goto bad;
+ break;
+ case 's':
+ str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
+ if (!str)
+ goto bad;
+ *sp = STRING_TO_JSVAL(str);
+ break;
+ case 'W':
+ str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
+ if (!str)
+ goto bad;
+ *sp = STRING_TO_JSVAL(str);
+ break;
+ case 'S':
+ str = va_arg(ap, JSString *);
+ *sp = STRING_TO_JSVAL(str);
+ break;
+ case 'o':
+ *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
+ break;
+ case 'f':
+ fun = va_arg(ap, JSFunction *);
+ *sp = fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL;
+ break;
+ case 'v':
+ *sp = va_arg(ap, jsval);
+ break;
+ default:
+ format--;
+ if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
+ JS_ADDRESSOF_VA_LIST(ap))) {
+ goto bad;
+ }
+ /* NB: the formatter already updated sp, so we continue here. */
+ continue;
+ }
+ sp++;
+ }
+
+ /*
+ * We may have overallocated stack due to a multi-character format code
+ * handled by a JSArgumentFormatter. Give back that stack space!
+ */
+ JS_ASSERT(sp <= argv + argc);
+ if (sp < argv + argc) {
+ /* Return slots not pushed to the current stack arena. */
+ cx->stackPool.current->avail = (jsuword)sp;
+
+ /* Reduce the count of slots the GC will scan in this stack segment. */
+ sh = cx->stackHeaders;
+ JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
+ sh->nslots -= argc - (sp - argv);
+ }
+ return argv;
+
+bad:
+ js_FreeStack(cx, *markp);
+ return NULL;
+}
+
+JS_PUBLIC_API(void)
+JS_PopArguments(JSContext *cx, void *mark)
+{
+ CHECK_REQUEST(cx);
+ js_FreeStack(cx, mark);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddArgumentFormatter(JSContext *cx, const char *format,
+ JSArgumentFormatter formatter)
+{
+ size_t length;
+ JSArgumentFormatMap **mpp, *map;
+
+ length = strlen(format);
+ mpp = &cx->argumentFormatMap;
+ while ((map = *mpp) != NULL) {
+ /* Insert before any shorter string to match before prefixes. */
+ if (map->length < length)
+ break;
+ if (map->length == length && !strcmp(map->format, format))
+ goto out;
+ mpp = &map->next;
+ }
+ map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
+ if (!map)
+ return JS_FALSE;
+ map->format = format;
+ map->length = length;
+ map->next = *mpp;
+ *mpp = map;
+out:
+ map->formatter = formatter;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(void)
+JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
+{
+ size_t length;
+ JSArgumentFormatMap **mpp, *map;
+
+ length = strlen(format);
+ mpp = &cx->argumentFormatMap;
+ while ((map = *mpp) != NULL) {
+ if (map->length == length && !strcmp(map->format, format)) {
+ *mpp = map->next;
+ JS_free(cx, map);
+ return;
+ }
+ mpp = &map->next;
+ }
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
+{
+ JSBool ok, b;
+ JSObject *obj;
+ JSFunction *fun;
+ JSString *str;
+ jsdouble d, *dp;
+
+ CHECK_REQUEST(cx);
+ switch (type) {
+ case JSTYPE_VOID:
+ *vp = JSVAL_VOID;
+ ok = JS_TRUE;
+ break;
+ case JSTYPE_OBJECT:
+ ok = js_ValueToObject(cx, v, &obj);
+ if (ok)
+ *vp = OBJECT_TO_JSVAL(obj);
+ break;
+ case JSTYPE_FUNCTION:
+ fun = js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
+ ok = (fun != NULL);
+ if (ok)
+ *vp = OBJECT_TO_JSVAL(fun->object);
+ break;
+ case JSTYPE_STRING:
+ str = js_ValueToString(cx, v);
+ ok = (str != NULL);
+ if (ok)
+ *vp = STRING_TO_JSVAL(str);
+ break;
+ case JSTYPE_NUMBER:
+ ok = js_ValueToNumber(cx, v, &d);
+ if (ok) {
+ dp = js_NewDouble(cx, d);
+ ok = (dp != NULL);
+ if (ok)
+ *vp = DOUBLE_TO_JSVAL(dp);
+ }
+ break;
+ case JSTYPE_BOOLEAN:
+ ok = js_ValueToBoolean(cx, v, &b);
+ if (ok)
+ *vp = BOOLEAN_TO_JSVAL(b);
+ break;
+ default: {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
+ numBuf);
+ ok = JS_FALSE;
+ break;
+ }
+ }
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToObject(cx, v, objp);
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_ValueToFunction(JSContext *cx, jsval v)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_ValueToConstructor(JSContext *cx, jsval v)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_ValueToString(JSContext *cx, jsval v)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToString(cx, v);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToNumber(cx, v, dp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToECMAInt32(cx, v, ip);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToECMAUint32(cx, v, ip);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToInt32(cx, v, ip);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToUint16(cx, v, ip);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
+{
+ CHECK_REQUEST(cx);
+ return js_ValueToBoolean(cx, v, bp);
+}
+
+JS_PUBLIC_API(JSType)
+JS_TypeOfValue(JSContext *cx, jsval v)
+{
+ JSType type;
+ JSObject *obj;
+ JSObjectOps *ops;
+ JSClass *clasp;
+
+ CHECK_REQUEST(cx);
+ if (JSVAL_IS_OBJECT(v)) {
+ /* XXX JSVAL_IS_OBJECT(v) is true for null too! Can we change ECMA? */
+ obj = JSVAL_TO_OBJECT(v);
+ if (obj &&
+ (ops = obj->map->ops,
+ ops == &js_ObjectOps
+ ? (clasp = OBJ_GET_CLASS(cx, obj),
+ clasp->call || clasp == &js_FunctionClass)
+ : ops->call != 0)) {
+ type = JSTYPE_FUNCTION;
+ } else {
+ type = JSTYPE_OBJECT;
+ }
+ } else if (JSVAL_IS_NUMBER(v)) {
+ type = JSTYPE_NUMBER;
+ } else if (JSVAL_IS_STRING(v)) {
+ type = JSTYPE_STRING;
+ } else if (JSVAL_IS_BOOLEAN(v)) {
+ type = JSTYPE_BOOLEAN;
+ } else {
+ type = JSTYPE_VOID;
+ }
+ return type;
+}
+
+JS_PUBLIC_API(const char *)
+JS_GetTypeName(JSContext *cx, JSType type)
+{
+ if ((uintN)type >= (uintN)JSTYPE_LIMIT)
+ return NULL;
+ return js_type_str[type];
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(JSRuntime *)
+JS_NewRuntime(uint32 maxbytes)
+{
+ JSRuntime *rt;
+
+#ifdef DEBUG
+ JS_BEGIN_MACRO
+ /*
+ * This code asserts that the numbers associated with the error names in
+ * jsmsg.def are monotonically increasing. It uses values for the error
+ * names enumerated in jscntxt.c. It's not a compiletime check, but it's
+ * better than nothing.
+ */
+ int errorNumber = 0;
+#define MSG_DEF(name, number, count, exception, format) \
+ JS_ASSERT(name == errorNumber++);
+#include "js.msg"
+#undef MSG_DEF
+ JS_END_MACRO;
+#endif /* DEBUG */
+
+ if (!js_InitScriptGlobals())
+ return NULL;
+ if (!js_InitStringGlobals())
+ return NULL;
+ rt = (JSRuntime *) malloc(sizeof(JSRuntime));
+ if (!rt)
+ return NULL;
+
+ /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
+ memset(rt, 0, sizeof(JSRuntime));
+ JS_INIT_CLIST(&rt->contextList);
+ JS_INIT_CLIST(&rt->trapList);
+ JS_INIT_CLIST(&rt->watchPointList);
+
+ if (!js_InitGC(rt, maxbytes))
+ goto bad;
+#ifdef JS_THREADSAFE
+ rt->gcLock = JS_NEW_LOCK();
+ if (!rt->gcLock)
+ goto bad;
+ rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->gcDone)
+ goto bad;
+ rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->requestDone)
+ goto bad;
+ js_SetupLocks(8, 16); /* this is asymmetric with JS_ShutDown. */
+ rt->rtLock = JS_NEW_LOCK();
+ if (!rt->rtLock)
+ goto bad;
+ rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->stateChange)
+ goto bad;
+ rt->setSlotLock = JS_NEW_LOCK();
+ if (!rt->setSlotLock)
+ goto bad;
+ rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock);
+ if (!rt->setSlotDone)
+ goto bad;
+ rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->scopeSharingDone)
+ goto bad;
+ rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;
+#endif
+ rt->propertyCache.empty = JS_TRUE;
+ if (!js_InitPropertyTree(rt))
+ goto bad;
+ return rt;
+
+bad:
+ JS_DestroyRuntime(rt);
+ return NULL;
+}
+
+JS_PUBLIC_API(void)
+JS_DestroyRuntime(JSRuntime *rt)
+{
+#ifdef DEBUG
+ /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
+ if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
+ JSContext *cx, *iter = NULL;
+ uintN cxcount = 0;
+ while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
+ cxcount++;
+ fprintf(stderr,
+"JS API usage error: %u contexts left in runtime upon JS_DestroyRuntime.\n",
+ cxcount);
+ }
+#endif
+
+ js_FinishAtomState(&rt->atomState);
+ js_FinishGC(rt);
+#ifdef JS_THREADSAFE
+ if (rt->gcLock)
+ JS_DESTROY_LOCK(rt->gcLock);
+ if (rt->gcDone)
+ JS_DESTROY_CONDVAR(rt->gcDone);
+ if (rt->requestDone)
+ JS_DESTROY_CONDVAR(rt->requestDone);
+ if (rt->rtLock)
+ JS_DESTROY_LOCK(rt->rtLock);
+ if (rt->stateChange)
+ JS_DESTROY_CONDVAR(rt->stateChange);
+ if (rt->setSlotLock)
+ JS_DESTROY_LOCK(rt->setSlotLock);
+ if (rt->setSlotDone)
+ JS_DESTROY_CONDVAR(rt->setSlotDone);
+ if (rt->scopeSharingDone)
+ JS_DESTROY_CONDVAR(rt->scopeSharingDone);
+#endif
+ js_FinishPropertyTree(rt);
+ free(rt);
+}
+
+JS_PUBLIC_API(void)
+JS_ShutDown(void)
+{
+ JS_ArenaShutDown();
+ js_FinishDtoa();
+ js_FreeScriptGlobals();
+ js_FreeStringGlobals();
+#ifdef JS_THREADSAFE
+ js_CleanupLocks();
+#endif
+}
+
+JS_PUBLIC_API(void *)
+JS_GetRuntimePrivate(JSRuntime *rt)
+{
+ return rt->data;
+}
+
+JS_PUBLIC_API(void)
+JS_SetRuntimePrivate(JSRuntime *rt, void *data)
+{
+ rt->data = data;
+}
+
+#ifdef JS_THREADSAFE
+
+JS_PUBLIC_API(void)
+JS_BeginRequest(JSContext *cx)
+{
+ JSRuntime *rt;
+
+ JS_ASSERT(cx->thread);
+ if (!cx->requestDepth) {
+ /* Wait until the GC is finished. */
+ rt = cx->runtime;
+ JS_LOCK_GC(rt);
+
+ /* NB: we use cx->thread here, not js_CurrentThreadId(). */
+ if (rt->gcThread != cx->thread) {
+ while (rt->gcLevel > 0)
+ JS_AWAIT_GC_DONE(rt);
+ }
+
+ /* Indicate that a request is running. */
+ rt->requestCount++;
+ cx->requestDepth = 1;
+ JS_UNLOCK_GC(rt);
+ return;
+ }
+ cx->requestDepth++;
+}
+
+JS_PUBLIC_API(void)
+JS_EndRequest(JSContext *cx)
+{
+ JSRuntime *rt;
+ JSScope *scope, **todop;
+ uintN nshares;
+
+ CHECK_REQUEST(cx);
+ JS_ASSERT(cx->requestDepth > 0);
+ if (cx->requestDepth == 1) {
+ /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
+ rt = cx->runtime;
+ JS_LOCK_GC(rt);
+ cx->requestDepth = 0;
+
+ /* See whether cx has any single-threaded scopes to start sharing. */
+ todop = &rt->scopeSharingTodo;
+ nshares = 0;
+ while ((scope = *todop) != NO_SCOPE_SHARING_TODO) {
+ if (scope->ownercx != cx) {
+ todop = &scope->u.link;
+ continue;
+ }
+ *todop = scope->u.link;
+ scope->u.link = NULL; /* null u.link for sanity ASAP */
+
+ /*
+ * If js_DropObjectMap returns null, we held the last ref to scope.
+ * The waiting thread(s) must have been killed, after which the GC
+ * collected the object that held this scope. Unlikely, because it
+ * requires that the GC ran (e.g., from a branch callback) during
+ * this request, but possible.
+ */
+ if (js_DropObjectMap(cx, &scope->map, NULL)) {
+ js_InitLock(&scope->lock);
+ scope->u.count = 0; /* NULL may not pun as 0 */
+ js_FinishSharingScope(rt, scope); /* set ownercx = NULL */
+ nshares++;
+ }
+ }
+ if (nshares)
+ JS_NOTIFY_ALL_CONDVAR(rt->scopeSharingDone);
+
+ /* Give the GC a chance to run if this was the last request running. */
+ JS_ASSERT(rt->requestCount > 0);
+ rt->requestCount--;
+ if (rt->requestCount == 0)
+ JS_NOTIFY_REQUEST_DONE(rt);
+
+ JS_UNLOCK_GC(rt);
+ return;
+ }
+
+ cx->requestDepth--;
+}
+
+/* Yield to pending GC operations, regardless of request depth */
+JS_PUBLIC_API(void)
+JS_YieldRequest(JSContext *cx)
+{
+ JSRuntime *rt;
+
+ JS_ASSERT(cx->thread);
+ CHECK_REQUEST(cx);
+
+ rt = cx->runtime;
+ JS_LOCK_GC(rt);
+ JS_ASSERT(rt->requestCount > 0);
+ rt->requestCount--;
+ if (rt->requestCount == 0)
+ JS_NOTIFY_REQUEST_DONE(rt);
+ JS_UNLOCK_GC(rt);
+ /* XXXbe give the GC or another request calling it a chance to run here?
+ Assumes FIFO scheduling */
+ JS_LOCK_GC(rt);
+ rt->requestCount++;
+ JS_UNLOCK_GC(rt);
+}
+
+JS_PUBLIC_API(jsrefcount)
+JS_SuspendRequest(JSContext *cx)
+{
+ jsrefcount saveDepth = cx->requestDepth;
+
+ while (cx->requestDepth)
+ JS_EndRequest(cx);
+ return saveDepth;
+}
+
+JS_PUBLIC_API(void)
+JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
+{
+ JS_ASSERT(!cx->requestDepth);
+ while (--saveDepth >= 0)
+ JS_BeginRequest(cx);
+}
+
+#endif /* JS_THREADSAFE */
+
+JS_PUBLIC_API(void)
+JS_Lock(JSRuntime *rt)
+{
+ JS_LOCK_RUNTIME(rt);
+}
+
+JS_PUBLIC_API(void)
+JS_Unlock(JSRuntime *rt)
+{
+ JS_UNLOCK_RUNTIME(rt);
+}
+
+JS_PUBLIC_API(JSContext *)
+JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
+{
+ return js_NewContext(rt, stackChunkSize);
+}
+
+JS_PUBLIC_API(void)
+JS_DestroyContext(JSContext *cx)
+{
+ js_DestroyContext(cx, JS_FORCE_GC);
+}
+
+JS_PUBLIC_API(void)
+JS_DestroyContextNoGC(JSContext *cx)
+{
+ js_DestroyContext(cx, JS_NO_GC);
+}
+
+JS_PUBLIC_API(void)
+JS_DestroyContextMaybeGC(JSContext *cx)
+{
+ js_DestroyContext(cx, JS_MAYBE_GC);
+}
+
+JS_PUBLIC_API(void *)
+JS_GetContextPrivate(JSContext *cx)
+{
+ return cx->data;
+}
+
+JS_PUBLIC_API(void)
+JS_SetContextPrivate(JSContext *cx, void *data)
+{
+ cx->data = data;
+}
+
+JS_PUBLIC_API(JSRuntime *)
+JS_GetRuntime(JSContext *cx)
+{
+ return cx->runtime;
+}
+
+JS_PUBLIC_API(JSContext *)
+JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
+{
+ return js_ContextIterator(rt, JS_TRUE, iterp);
+}
+
+JS_PUBLIC_API(JSVersion)
+JS_GetVersion(JSContext *cx)
+{
+ return cx->version;
+}
+
+JS_PUBLIC_API(JSVersion)
+JS_SetVersion(JSContext *cx, JSVersion version)
+{
+ JSVersion oldVersion;
+
+ oldVersion = cx->version;
+ if (version == oldVersion)
+ return oldVersion;
+
+ cx->version = version;
+
+#if !JS_BUG_FALLIBLE_EQOPS
+ if (cx->version == JSVERSION_1_2) {
+ cx->jsop_eq = JSOP_NEW_EQ;
+ cx->jsop_ne = JSOP_NEW_NE;
+ } else {
+ cx->jsop_eq = JSOP_EQ;
+ cx->jsop_ne = JSOP_NE;
+ }
+#endif /* !JS_BUG_FALLIBLE_EQOPS */
+
+ return oldVersion;
+}
+
+static struct v2smap {
+ JSVersion version;
+ const char *string;
+} v2smap[] = {
+ {JSVERSION_1_0, "1.0"},
+ {JSVERSION_1_1, "1.1"},
+ {JSVERSION_1_2, "1.2"},
+ {JSVERSION_1_3, "1.3"},
+ {JSVERSION_1_4, "1.4"},
+ {JSVERSION_ECMA_3, "ECMAv3"},
+ {JSVERSION_1_5, "1.5"},
+ {JSVERSION_DEFAULT, "default"},
+ {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
+};
+
+JS_PUBLIC_API(const char *)
+JS_VersionToString(JSVersion version)
+{
+ int i;
+
+ for (i = 0; v2smap[i].string; i++)
+ if (v2smap[i].version == version)
+ return v2smap[i].string;
+ return "unknown";
+}
+
+JS_PUBLIC_API(JSVersion)
+JS_StringToVersion(const char *string)
+{
+ int i;
+
+ for (i = 0; v2smap[i].string; i++)
+ if (strcmp(v2smap[i].string, string) == 0)
+ return v2smap[i].version;
+ return JSVERSION_UNKNOWN;
+}
+
+JS_PUBLIC_API(uint32)
+JS_GetOptions(JSContext *cx)
+{
+ return cx->options;
+}
+
+JS_PUBLIC_API(uint32)
+JS_SetOptions(JSContext *cx, uint32 options)
+{
+ uint32 oldopts = cx->options;
+ cx->options = options;
+ return oldopts;
+}
+
+JS_PUBLIC_API(uint32)
+JS_ToggleOptions(JSContext *cx, uint32 options)
+{
+ uint32 oldopts = cx->options;
+ cx->options ^= options;
+ return oldopts;
+}
+
+JS_PUBLIC_API(const char *)
+JS_GetImplementationVersion(void)
+{
+ return "JavaScript-C 1.5 pre-release 6 2004-01-27";
+}
+
+
+JS_PUBLIC_API(JSObject *)
+JS_GetGlobalObject(JSContext *cx)
+{
+ return cx->globalObject;
+}
+
+JS_PUBLIC_API(void)
+JS_SetGlobalObject(JSContext *cx, JSObject *obj)
+{
+ cx->globalObject = obj;
+}
+
+static JSObject *
+InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
+{
+ JSDHashTable *table;
+ JSBool resolving;
+ JSRuntime *rt;
+ JSResolvingKey key;
+ JSResolvingEntry *entry;
+ JSObject *fun_proto, *obj_proto;
+
+ /* If cx has no global object, use obj so prototypes can be found. */
+ if (!cx->globalObject)
+ cx->globalObject = obj;
+
+ /* Record Function and Object in cx->resolvingTable, if we are resolving. */
+ table = cx->resolvingTable;
+ resolving = (table && table->entryCount);
+ if (resolving) {
+ rt = cx->runtime;
+ key.obj = obj;
+ key.id = (jsid) rt->atomState.FunctionAtom;
+ entry = (JSResolvingEntry *)
+ JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
+ if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
+ /* Already resolving Function, record Object too. */
+ JS_ASSERT(entry->key.obj == obj);
+ key.id = (jsid) rt->atomState.ObjectAtom;
+ entry = (JSResolvingEntry *)
+ JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
+ }
+ if (!entry) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ JS_ASSERT(!entry->key.obj && entry->flags == 0);
+ entry->key = key;
+ entry->flags = JSRESFLAG_LOOKUP;
+ }
+
+ /* Initialize the function class first so constructors can be made. */
+ fun_proto = js_InitFunctionClass(cx, obj);
+ if (!fun_proto)
+ goto out;
+
+ /* Initialize the object class next so Object.prototype works. */
+ obj_proto = js_InitObjectClass(cx, obj);
+ if (!obj_proto) {
+ fun_proto = NULL;
+ goto out;
+ }
+
+ /* Function.prototype and the global object delegate to Object.prototype. */
+ OBJ_SET_PROTO(cx, fun_proto, obj_proto);
+ if (!OBJ_GET_PROTO(cx, obj))
+ OBJ_SET_PROTO(cx, obj, obj_proto);
+
+out:
+ /* If resolving, remove the other entry (Object or Function) from table. */
+ if (resolving)
+ JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
+ return fun_proto;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_InitStandardClasses(JSContext *cx, JSObject *obj)
+{
+ CHECK_REQUEST(cx);
+
+#if JS_HAS_UNDEFINED
+{
+ /* Define a top-level property 'undefined' with the undefined value. */
+ JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
+ JSPROP_PERMANENT, NULL)) {
+ return JS_FALSE;
+ }
+}
+#endif
+
+ /* Function and Object require cooperative bootstrapping magic. */
+ if (!InitFunctionAndObjectClasses(cx, obj))
+ return JS_FALSE;
+
+ /* Initialize the rest of the standard objects and functions. */
+ return js_InitArrayClass(cx, obj) &&
+ js_InitBooleanClass(cx, obj) &&
+ js_InitMathClass(cx, obj) &&
+ js_InitNumberClass(cx, obj) &&
+ js_InitStringClass(cx, obj) &&
+#if JS_HAS_CALL_OBJECT
+ js_InitCallClass(cx, obj) &&
+#endif
+#if JS_HAS_REGEXPS
+ js_InitRegExpClass(cx, obj) &&
+#endif
+#if JS_HAS_SCRIPT_OBJECT
+ js_InitScriptClass(cx, obj) &&
+#endif
+#if JS_HAS_ERROR_EXCEPTIONS
+ js_InitExceptionClasses(cx, obj) &&
+#endif
+#if JS_HAS_FILE_OBJECT
+ js_InitFileClass(cx, obj, JS_TRUE) &&
+#endif
+ js_InitDateClass(cx, obj);
+}
+
+#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
+#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
+
+/*
+ * Table of class initializers and their atom offsets in rt->atomState.
+ * If you add a "standard" class, remember to update this table.
+ */
+static struct {
+ JSObjectOp init;
+ size_t atomOffset;
+} standard_class_atoms[] = {
+ {InitFunctionAndObjectClasses, ATOM_OFFSET(Function)},
+ {InitFunctionAndObjectClasses, ATOM_OFFSET(Object)},
+ {js_InitArrayClass, ATOM_OFFSET(Array)},
+ {js_InitBooleanClass, ATOM_OFFSET(Boolean)},
+ {js_InitDateClass, ATOM_OFFSET(Date)},
+ {js_InitMathClass, ATOM_OFFSET(Math)},
+ {js_InitNumberClass, ATOM_OFFSET(Number)},
+ {js_InitStringClass, ATOM_OFFSET(String)},
+#if JS_HAS_CALL_OBJECT
+ {js_InitCallClass, ATOM_OFFSET(Call)},
+#endif
+#if JS_HAS_ERROR_EXCEPTIONS
+ {js_InitExceptionClasses, ATOM_OFFSET(Error)},
+#endif
+#if JS_HAS_REGEXPS
+ {js_InitRegExpClass, ATOM_OFFSET(RegExp)},
+#endif
+#if JS_HAS_SCRIPT_OBJECT
+ {js_InitScriptClass, ATOM_OFFSET(Script)},
+#endif
+ {NULL, 0}
+};
+
+/*
+ * Table of top-level function and constant names and their init functions.
+ * If you add a "standard" global function or property, remember to update
+ * this table.
+ */
+typedef struct JSStdName {
+ JSObjectOp init;
+ size_t atomOffset; /* offset of atom pointer in JSAtomState */
+ const char *name; /* null if atom is pre-pinned, else name */
+} JSStdName;
+
+static JSAtom *
+StdNameToAtom(JSContext *cx, JSStdName *stdn)
+{
+ size_t offset;
+ JSAtom *atom;
+ const char *name;
+
+ offset = stdn->atomOffset;
+ atom = OFFSET_TO_ATOM(cx->runtime, offset);
+ if (!atom) {
+ name = stdn->name;
+ if (name) {
+ atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
+ OFFSET_TO_ATOM(cx->runtime, offset) = atom;
+ }
+ }
+ return atom;
+}
+
+#define EAGERLY_PINNED_ATOM(name) ATOM_OFFSET(name), NULL
+#define LAZILY_PINNED_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
+
+static JSStdName standard_class_names[] = {
+ /* ECMA requires that eval be a direct property of the global object. */
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(eval)},
+
+ /* Global properties and functions defined by the Number class. */
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(NaN)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(Infinity)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(isNaN)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(isFinite)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(parseFloat)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(parseInt)},
+
+ /* String global functions. */
+ {js_InitStringClass, LAZILY_PINNED_ATOM(escape)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(unescape)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURI)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURI)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURIComponent)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURIComponent)},
+#if JS_HAS_UNEVAL
+ {js_InitStringClass, LAZILY_PINNED_ATOM(uneval)},
+#endif
+
+ /* Exception constructors. */
+#if JS_HAS_ERROR_EXCEPTIONS
+ {js_InitExceptionClasses, EAGERLY_PINNED_ATOM(Error)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(InternalError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(EvalError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(RangeError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(ReferenceError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(SyntaxError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(TypeError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(URIError)},
+#endif
+
+ {NULL, 0, NULL}
+};
+
+static JSStdName object_prototype_names[] = {
+ /* Object.prototype properties (global delegates to Object.prototype). */
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(proto)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(parent)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(count)},
+#if JS_HAS_TOSOURCE
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(toSource)},
+#endif
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(toString)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(toLocaleString)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(valueOf)},
+#if JS_HAS_OBJ_WATCHPOINT
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(watch)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(unwatch)},
+#endif
+#if JS_HAS_NEW_OBJ_METHODS
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(hasOwnProperty)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(isPrototypeOf)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(propertyIsEnumerable)},
+#endif
+#if JS_HAS_GETTER_SETTER
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(defineGetter)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(defineSetter)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupGetter)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupSetter)},
+#endif
+
+ {NULL, 0, NULL}
+};
+
+#undef EAGERLY_PINNED_ATOM
+#undef LAZILY_PINNED_ATOM
+
+JS_PUBLIC_API(JSBool)
+JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
+ JSBool *resolved)
+{
+ JSString *idstr;
+ JSRuntime *rt;
+ JSAtom *atom;
+ JSObjectOp init;
+ uintN i;
+
+ CHECK_REQUEST(cx);
+ *resolved = JS_FALSE;
+
+ if (!JSVAL_IS_STRING(id))
+ return JS_TRUE;
+ idstr = JSVAL_TO_STRING(id);
+ rt = cx->runtime;
+
+#if JS_HAS_UNDEFINED
+ /* See if we're resolving 'undefined', and define it if so. */
+ atom = rt->atomState.typeAtoms[JSTYPE_VOID];
+ if (idstr == ATOM_TO_STRING(atom)) {
+ *resolved = JS_TRUE;
+ return OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
+ JSPROP_PERMANENT, NULL);
+ }
+#endif
+
+ /* Try for class constructors/prototypes named by well-known atoms. */
+ init = NULL;
+ for (i = 0; standard_class_atoms[i].init; i++) {
+ atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
+ if (idstr == ATOM_TO_STRING(atom)) {
+ init = standard_class_atoms[i].init;
+ break;
+ }
+ }
+
+ if (!init) {
+ /* Try less frequently used top-level functions and constants. */
+ for (i = 0; standard_class_names[i].init; i++) {
+ atom = StdNameToAtom(cx, &standard_class_names[i]);
+ if (!atom)
+ return JS_FALSE;
+ if (idstr == ATOM_TO_STRING(atom)) {
+ init = standard_class_names[i].init;
+ break;
+ }
+ }
+
+ if (!init && !OBJ_GET_PROTO(cx, obj)) {
+ /*
+ * Try even less frequently used names delegated from the global
+ * object to Object.prototype, but only if the Object class hasn't
+ * yet been initialized.
+ */
+ for (i = 0; object_prototype_names[i].init; i++) {
+ atom = StdNameToAtom(cx, &object_prototype_names[i]);
+ if (!atom)
+ return JS_FALSE;
+ if (idstr == ATOM_TO_STRING(atom)) {
+ init = standard_class_names[i].init;
+ break;
+ }
+ }
+ }
+ }
+
+ if (init) {
+ if (!init(cx, obj))
+ return JS_FALSE;
+ *resolved = JS_TRUE;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+HasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom, JSBool *ownp)
+{
+ JSObject *pobj;
+ JSProperty *prop;
+
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
+ return JS_FALSE;
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ *ownp = (pobj == obj && prop);
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
+{
+ JSRuntime *rt;
+ JSAtom *atom;
+ JSBool found;
+ uintN i;
+
+ CHECK_REQUEST(cx);
+ rt = cx->runtime;
+
+#if JS_HAS_UNDEFINED
+ /* See if we need to bind 'undefined' and define it if so. */
+ atom = rt->atomState.typeAtoms[JSTYPE_VOID];
+ if (!HasOwnProperty(cx, obj, atom, &found))
+ return JS_FALSE;
+ if (!found &&
+ !OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
+ JSPROP_PERMANENT, NULL)) {
+ return JS_FALSE;
+ }
+#endif
+
+ /* Initialize any classes that have not been resolved yet. */
+ for (i = 0; standard_class_atoms[i].init; i++) {
+ atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
+ if (!HasOwnProperty(cx, obj, atom, &found))
+ return JS_FALSE;
+ if (!found && !standard_class_atoms[i].init(cx, obj))
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+#undef ATOM_OFFSET
+#undef OFFSET_TO_ATOM
+
+JS_PUBLIC_API(JSObject *)
+JS_GetScopeChain(JSContext *cx)
+{
+ return cx->fp ? cx->fp->scopeChain : NULL;
+}
+
+JS_PUBLIC_API(void *)
+JS_malloc(JSContext *cx, size_t nbytes)
+{
+ void *p;
+
+ JS_ASSERT(nbytes != 0);
+ if (nbytes == 0)
+ nbytes = 1;
+ cx->runtime->gcMallocBytes += nbytes;
+ p = malloc(nbytes);
+ if (!p)
+ JS_ReportOutOfMemory(cx);
+ return p;
+}
+
+JS_PUBLIC_API(void *)
+JS_realloc(JSContext *cx, void *p, size_t nbytes)
+{
+ p = realloc(p, nbytes);
+ if (!p)
+ JS_ReportOutOfMemory(cx);
+ return p;
+}
+
+JS_PUBLIC_API(void)
+JS_free(JSContext *cx, void *p)
+{
+ if (p)
+ free(p);
+}
+
+JS_PUBLIC_API(char *)
+JS_strdup(JSContext *cx, const char *s)
+{
+ size_t n;
+ void *p;
+
+ n = strlen(s) + 1;
+ p = JS_malloc(cx, n);
+ if (!p)
+ return NULL;
+ return (char *)memcpy(p, s, n);
+}
+
+JS_PUBLIC_API(jsdouble *)
+JS_NewDouble(JSContext *cx, jsdouble d)
+{
+ CHECK_REQUEST(cx);
+ return js_NewDouble(cx, d);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
+{
+ CHECK_REQUEST(cx);
+ return js_NewDoubleValue(cx, d, rval);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
+{
+ CHECK_REQUEST(cx);
+ return js_NewNumberValue(cx, d, rval);
+}
+
+#undef JS_AddRoot
+JS_PUBLIC_API(JSBool)
+JS_AddRoot(JSContext *cx, void *rp)
+{
+ CHECK_REQUEST(cx);
+ return js_AddRoot(cx, rp, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
+{
+ return js_AddRootRT(rt, rp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_RemoveRoot(JSContext *cx, void *rp)
+{
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, rp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_RemoveRootRT(JSRuntime *rt, void *rp)
+{
+ return js_RemoveRoot(rt, rp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
+{
+ CHECK_REQUEST(cx);
+ return js_AddRoot(cx, rp, name);
+}
+
+JS_PUBLIC_API(void)
+JS_ClearNewbornRoots(JSContext *cx)
+{
+ uintN i;
+
+ for (i = 0; i < GCX_NTYPES; i++)
+ cx->newborn[i] = NULL;
+ cx->lastAtom = NULL;
+}
+
+#include "jshash.h" /* Added by JSIFY */
+
+#ifdef DEBUG
+
+typedef struct NamedRootDumpArgs {
+ void (*dump)(const char *name, void *rp, void *data);
+ void *data;
+} NamedRootDumpArgs;
+
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
+ void *arg)
+{
+ NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
+
+ if (rhe->name)
+ args->dump(rhe->name, rhe->root, args->data);
+ return JS_DHASH_NEXT;
+}
+
+JS_PUBLIC_API(void)
+JS_DumpNamedRoots(JSRuntime *rt,
+ void (*dump)(const char *name, void *rp, void *data),
+ void *data)
+{
+ NamedRootDumpArgs args;
+
+ args.dump = dump;
+ args.data = data;
+ JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
+}
+
+#endif /* DEBUG */
+
+typedef struct GCRootMapArgs {
+ JSGCRootMapFun map;
+ void *data;
+} GCRootMapArgs;
+
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
+ void *arg)
+{
+ GCRootMapArgs *args = (GCRootMapArgs *) arg;
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
+ intN mapflags;
+ JSDHashOperator op;
+
+ mapflags = args->map(rhe->root, rhe->name, args->data);
+
+#if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \
+ JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \
+ JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
+ op = (JSDHashOperator)mapflags;
+#else
+ op = JS_DHASH_NEXT;
+ if (mapflags & JS_MAP_GCROOT_STOP)
+ op |= JS_DHASH_STOP;
+ if (mapflags & JS_MAP_GCROOT_REMOVE)
+ op |= JS_DHASH_REMOVE;
+#endif
+
+ return op;
+}
+
+JS_PUBLIC_API(uint32)
+JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
+{
+ GCRootMapArgs args;
+ uint32 rv;
+
+ args.map = map;
+ args.data = data;
+ JS_LOCK_GC(rt);
+ rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
+ JS_UNLOCK_GC(rt);
+ return rv;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_LockGCThing(JSContext *cx, void *thing)
+{
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ ok = js_LockGCThing(cx, thing);
+ if (!ok)
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_LOCK);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_LockGCThingRT(JSRuntime *rt, void *thing)
+{
+ return js_LockGCThingRT(rt, thing);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_UnlockGCThing(JSContext *cx, void *thing)
+{
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ ok = js_UnlockGCThingRT(cx->runtime, thing);
+ if (!ok)
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
+{
+ return js_UnlockGCThingRT(rt, thing);
+}
+
+JS_PUBLIC_API(void)
+JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
+{
+ JS_ASSERT(cx->runtime->gcLevel > 0);
+#ifdef JS_THREADSAFE
+ JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
+#endif
+
+ GC_MARK(cx, thing, name, arg);
+}
+
+JS_PUBLIC_API(void)
+JS_GC(JSContext *cx)
+{
+ /* Don't nuke active arenas if executing or compiling. */
+ if (cx->stackPool.current == &cx->stackPool.first)
+ JS_FinishArenaPool(&cx->stackPool);
+ if (cx->tempPool.current == &cx->tempPool.first)
+ JS_FinishArenaPool(&cx->tempPool);
+ js_ForceGC(cx, 0);
+}
+
+JS_PUBLIC_API(void)
+JS_MaybeGC(JSContext *cx)
+{
+ JSRuntime *rt;
+ uint32 bytes, lastBytes;
+
+ rt = cx->runtime;
+ bytes = rt->gcBytes;
+ lastBytes = rt->gcLastBytes;
+ if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) ||
+ rt->gcMallocBytes > rt->gcMaxBytes) {
+ /*
+ * Run the GC if we have half again as many bytes of GC-things as
+ * the last time we GC'd, or if we have malloc'd more bytes through
+ * JS_malloc than we were told to allocate by JS_NewRuntime.
+ */
+ JS_GC(cx);
+ }
+}
+
+JS_PUBLIC_API(JSGCCallback)
+JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
+{
+ return JS_SetGCCallbackRT(cx->runtime, cb);
+}
+
+JS_PUBLIC_API(JSGCCallback)
+JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
+{
+ JSGCCallback oldcb;
+
+ oldcb = rt->gcCallback;
+ rt->gcCallback = cb;
+ return oldcb;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
+{
+ JS_ASSERT(thing);
+ return js_IsAboutToBeFinalized(cx, thing);
+}
+
+JS_PUBLIC_API(intN)
+JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
+{
+ return js_ChangeExternalStringFinalizer(NULL, finalizer);
+}
+
+JS_PUBLIC_API(intN)
+JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
+{
+ return js_ChangeExternalStringFinalizer(finalizer, NULL);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
+{
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
+
+ str = (JSString *) js_AllocGCThing(cx, (uintN) type);
+ if (!str)
+ return NULL;
+ str->length = length;
+ str->chars = chars;
+ return str;
+}
+
+JS_PUBLIC_API(intN)
+JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
+{
+ uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
+
+ if (type >= GCX_EXTERNAL_STRING)
+ return (intN)type;
+ JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
+ return -1;
+}
+
+#ifdef DEBUG
+static void
+CheckStackGrowthDirection(int *dummy1addr, jsuword limitAddr)
+{
+ int dummy2;
+
+#if JS_STACK_GROWTH_DIRECTION > 0
+ JS_ASSERT(dummy1addr < &dummy2);
+ JS_ASSERT((jsuword)&dummy2 < limitAddr);
+#else
+ /* Stack grows downward, the common case on modern architectures. */
+ JS_ASSERT(&dummy2 < dummy1addr);
+ JS_ASSERT(limitAddr < (jsuword)&dummy2);
+#endif
+}
+#endif
+
+JS_PUBLIC_API(void)
+JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
+{
+#ifdef DEBUG
+ int dummy1;
+
+ CheckStackGrowthDirection(&dummy1, limitAddr);
+#endif
+
+#if JS_STACK_GROWTH_DIRECTION > 0
+ if (limitAddr == 0)
+ limitAddr = (jsuword)-1;
+#endif
+ cx->stackLimit = limitAddr;
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(void)
+JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
+{
+ JS_free(cx, ida);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ if (JSVAL_IS_INT(v)) {
+ *idp = v;
+ } else {
+ atom = js_ValueToStringAtom(cx, v);
+ if (!atom)
+ return JS_FALSE;
+ *idp = (jsid)atom;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
+{
+ CHECK_REQUEST(cx);
+ *vp = ID_TO_VALUE(id);
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_EnumerateStub(JSContext *cx, JSObject *obj)
+{
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
+{
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+{
+#if JS_BUG_EAGER_TOSTRING
+ if (type == JSTYPE_STRING)
+ return JS_TRUE;
+#endif
+ return js_TryValueOf(cx, obj, type, vp);
+}
+
+JS_PUBLIC_API(void)
+JS_FinalizeStub(JSContext *cx, JSObject *obj)
+{
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
+ JSClass *clasp, JSNative constructor, uintN nargs,
+ JSPropertySpec *ps, JSFunctionSpec *fs,
+ JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
+{
+ JSAtom *atom;
+ JSObject *proto, *ctor;
+ JSBool named;
+ JSFunction *fun;
+ jsval junk;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
+ if (!atom)
+ return NULL;
+
+ /* Create a prototype object for this class. */
+ proto = js_NewObject(cx, clasp, parent_proto, obj);
+ if (!proto)
+ return NULL;
+
+ if (!constructor) {
+ /* Lacking a constructor, name the prototype (e.g., Math). */
+ named = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, OBJECT_TO_JSVAL(proto),
+ NULL, NULL, 0, NULL);
+ if (!named)
+ goto bad;
+ ctor = proto;
+ } else {
+ /* Define the constructor function in obj's scope. */
+ fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
+ named = (fun != NULL);
+ if (!fun)
+ goto bad;
+
+ /*
+ * Remember the class this function is a constructor for so that
+ * we know to create an object of this class when we call the
+ * constructor.
+ */
+ fun->clasp = clasp;
+
+ /* Connect constructor and prototype by named properties. */
+ ctor = fun->object;
+ if (!js_SetClassPrototype(cx, ctor, proto,
+ JSPROP_READONLY | JSPROP_PERMANENT)) {
+ goto bad;
+ }
+
+ /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
+ if (OBJ_GET_CLASS(cx, ctor) == clasp) {
+ /* XXXMLM - this fails in framesets that are writing over
+ * themselves!
+ * JS_ASSERT(!OBJ_GET_PROTO(cx, ctor));
+ */
+ OBJ_SET_PROTO(cx, ctor, proto);
+ }
+ }
+
+ /* Add properties and methods to the prototype and the constructor. */
+ if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
+ (fs && !JS_DefineFunctions(cx, proto, fs)) ||
+ (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
+ (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
+ goto bad;
+ }
+ return proto;
+
+bad:
+ if (named)
+ (void) OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, &junk);
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+}
+
+#ifdef JS_THREADSAFE
+JS_PUBLIC_API(JSClass *)
+JS_GetClass(JSContext *cx, JSObject *obj)
+{
+ return (JSClass *)
+ JSVAL_TO_PRIVATE(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_CLASS));
+}
+#else
+JS_PUBLIC_API(JSClass *)
+JS_GetClass(JSObject *obj)
+{
+ return LOCKED_OBJ_GET_CLASS(obj);
+}
+#endif
+
+JS_PUBLIC_API(JSBool)
+JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
+{
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ if (OBJ_GET_CLASS(cx, obj) == clasp)
+ return JS_TRUE;
+ if (argv) {
+ fun = js_ValueToFunction(cx, &argv[-2], 0);
+ if (fun) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_INCOMPATIBLE_PROTO,
+ clasp->name, JS_GetFunctionName(fun),
+ OBJ_GET_CLASS(cx, obj)->name);
+ }
+ }
+ return JS_FALSE;
+}
+
+JS_PUBLIC_API(void *)
+JS_GetPrivate(JSContext *cx, JSObject *obj)
+{
+ jsval v;
+
+ JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
+ v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ if (!JSVAL_IS_INT(v))
+ return NULL;
+ return JSVAL_TO_PRIVATE(v);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
+{
+ JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(void *)
+JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
+ jsval *argv)
+{
+ if (!JS_InstanceOf(cx, obj, clasp, argv))
+ return NULL;
+ return JS_GetPrivate(cx, obj);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetPrototype(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+
+ CHECK_REQUEST(cx);
+ proto = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PROTO));
+
+ /* Beware ref to dead object (we may be called from obj's finalizer). */
+ return proto && proto->map ? proto : NULL;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
+{
+ CHECK_REQUEST(cx);
+ if (obj->map->ops->setProto)
+ return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto));
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetParent(JSContext *cx, JSObject *obj)
+{
+ JSObject *parent;
+
+ parent = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PARENT));
+
+ /* Beware ref to dead object (we may be called from obj's finalizer). */
+ return parent && parent->map ? parent : NULL;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
+{
+ CHECK_REQUEST(cx);
+ if (obj->map->ops->setParent)
+ return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent));
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetConstructor(JSContext *cx, JSObject *proto)
+{
+ jsval cval;
+
+ CHECK_REQUEST(cx);
+ if (!OBJ_GET_PROPERTY(cx, proto,
+ (jsid)cx->runtime->atomState.constructorAtom,
+ &cval)) {
+ return NULL;
+ }
+ if (!JSVAL_IS_FUNCTION(cx, cval)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
+ OBJ_GET_CLASS(cx, proto)->name);
+ return NULL;
+ }
+ return JSVAL_TO_OBJECT(cval);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
+{
+ *idp = (jsid) obj;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
+{
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ return js_NewObject(cx, clasp, proto, parent);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
+{
+ JSScope *scope;
+ JSIdArray *ida;
+ uint32 nslots;
+ jsval v, *vp, *end;
+
+ if (!OBJ_IS_NATIVE(obj)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_SEAL_OBJECT,
+ OBJ_GET_CLASS(cx, obj)->name);
+ return JS_FALSE;
+ }
+
+ scope = OBJ_SCOPE(obj);
+
+#if defined JS_THREADSAFE && defined DEBUG
+ /* Insist on scope being used exclusively by cx's thread. */
+ if (scope->ownercx != cx) {
+ JS_LOCK_OBJ(cx, obj);
+ JS_ASSERT(OBJ_SCOPE(obj) == scope);
+ JS_ASSERT(scope->ownercx == cx);
+ JS_UNLOCK_SCOPE(cx, scope);
+ }
+#endif
+
+ /* Nothing to do if obj's scope is already sealed. */
+ if (SCOPE_IS_SEALED(scope))
+ return JS_TRUE;
+
+ /* XXX Enumerate lazy properties now, as they can't be added later. */
+ ida = JS_Enumerate(cx, obj);
+ if (!ida)
+ return JS_FALSE;
+ JS_DestroyIdArray(cx, ida);
+
+ /* Ensure that obj has its own, mutable scope, and seal that scope. */
+ JS_LOCK_OBJ(cx, obj);
+ scope = js_GetMutableScope(cx, obj);
+ if (scope)
+ SCOPE_SET_SEALED(scope);
+ JS_UNLOCK_SCOPE(cx, scope);
+ if (!scope)
+ return JS_FALSE;
+
+ /* If we are not sealing an entire object graph, we're done. */
+ if (!deep)
+ return JS_TRUE;
+
+ /* Walk obj->slots and if any value is a non-null object, seal it. */
+ nslots = JS_MIN(scope->map.freeslot, scope->map.nslots);
+ for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
+ v = *vp;
+ if (JSVAL_IS_PRIMITIVE(v))
+ continue;
+ if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent)
+{
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent, uintN argc, jsval *argv)
+{
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
+}
+
+static JSBool
+DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ uintN flags, intN tinyid)
+{
+ jsid id;
+ JSAtom *atom;
+
+ if (attrs & JSPROP_INDEX) {
+ id = INT_TO_JSVAL((jsint)name);
+ atom = NULL;
+ attrs &= ~JSPROP_INDEX;
+ } else {
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ id = (jsid)atom;
+ }
+ if (flags != 0 && OBJ_IS_NATIVE(obj)) {
+ return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
+ attrs, flags, tinyid, NULL);
+ }
+ return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
+ NULL);
+}
+
+#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
+
+static JSBool
+DefineUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ uintN flags, intN tinyid)
+{
+ JSAtom *atom;
+
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name,namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ if (flags != 0 && OBJ_IS_NATIVE(obj)) {
+ return js_DefineNativeProperty(cx, obj, (jsid)atom, value,
+ getter, setter, attrs, flags, tinyid,
+ NULL);
+ }
+ return OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, value, getter, setter,
+ attrs, NULL);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
+ JSObject *proto, uintN attrs)
+{
+ JSObject *nobj;
+
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ nobj = js_NewObject(cx, clasp, proto, obj);
+ if (!nobj)
+ return NULL;
+ if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
+ 0, 0)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ return nobj;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
+{
+ JSBool ok;
+ jsval value;
+ uintN flags;
+
+ CHECK_REQUEST(cx);
+ for (ok = JS_TRUE; cds->name; cds++) {
+ ok = js_NewNumberValue(cx, cds->dval, &value);
+ if (!ok)
+ break;
+ flags = cds->flags;
+ if (!flags)
+ flags = JSPROP_READONLY | JSPROP_PERMANENT;
+ ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
+ if (!ok)
+ break;
+ }
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
+{
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ for (ok = JS_TRUE; ps->name; ps++) {
+ ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
+ ps->getter, ps->setter, ps->flags,
+ SPROP_HAS_SHORTID, ps->tinyid);
+ if (!ok)
+ break;
+ }
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
+{
+ CHECK_REQUEST(cx);
+ return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
+ int8 tinyid, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs)
+{
+ CHECK_REQUEST(cx);
+ return DefineProperty(cx, obj, name, value, getter, setter, attrs,
+ SPROP_HAS_SHORTID, tinyid);
+}
+
+static JSBool
+LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
+ JSProperty **propp)
+{
+ JSAtom *atom;
+
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, objp, propp);
+}
+
+static JSBool
+LookupUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ JSObject **objp, JSProperty **propp)
+{
+ JSAtom *atom;
+
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name,namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, objp, propp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
+ const char *alias)
+{
+ JSObject *obj2;
+ JSProperty *prop;
+ JSAtom *atom;
+ JSBool ok;
+ JSScopeProperty *sprop;
+
+ CHECK_REQUEST(cx);
+ if (!LookupProperty(cx, obj, name, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ js_ReportIsNotDefined(cx, name);
+ return JS_FALSE;
+ }
+ if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
+ alias, name, OBJ_GET_CLASS(cx, obj2)->name);
+ return JS_FALSE;
+ }
+ atom = js_Atomize(cx, alias, strlen(alias), 0);
+ if (!atom) {
+ ok = JS_FALSE;
+ } else {
+ sprop = (JSScopeProperty *)prop;
+ ok = (js_AddNativeProperty(cx, obj, (jsid)atom,
+ sprop->getter, sprop->setter, sprop->slot,
+ sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
+ sprop->shortid)
+ != NULL);
+ }
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+}
+
+static jsval
+LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
+{
+ JSScopeProperty *sprop;
+ jsval rval;
+
+ if (!prop) {
+ /* XXX bad API: no way to tell "not defined" from "void value" */
+ return JSVAL_VOID;
+ }
+ if (OBJ_IS_NATIVE(obj2)) {
+ /* Peek at the native property's slot value, without doing a Get. */
+ sprop = (JSScopeProperty *)prop;
+ rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
+ ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
+ : JSVAL_TRUE;
+ } else {
+ /* XXX bad API: no way to return "defined but value unknown" */
+ rval = JSVAL_TRUE;
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ return rval;
+}
+
+static JSBool
+GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
+ uintN *attrsp, JSBool *foundp)
+{
+ JSObject *obj2;
+ JSProperty *prop;
+ JSBool ok;
+
+ if (!atom)
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop || obj != obj2) {
+ *foundp = JS_FALSE;
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ return JS_TRUE;
+ }
+
+ *foundp = JS_TRUE;
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, (jsid)atom, prop, attrsp);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+}
+
+static JSBool
+SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
+ uintN attrs, JSBool *foundp)
+{
+ JSObject *obj2;
+ JSProperty *prop;
+ JSBool ok;
+
+ if (!atom)
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop || obj != obj2) {
+ *foundp = JS_FALSE;
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ return JS_TRUE;
+ }
+
+ *foundp = JS_TRUE;
+ ok = OBJ_SET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+}
+
+
+JS_PUBLIC_API(JSBool)
+JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+ uintN *attrsp, JSBool *foundp)
+{
+ CHECK_REQUEST(cx);
+ return GetPropertyAttributes(cx, obj,
+ js_Atomize(cx, name, strlen(name), 0),
+ attrsp, foundp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+ uintN attrs, JSBool *foundp)
+{
+ CHECK_REQUEST(cx);
+ return SetPropertyAttributes(cx, obj,
+ js_Atomize(cx, name, strlen(name), 0),
+ attrs, foundp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
+{
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = LookupProperty(cx, obj, name, &obj2, &prop);
+ if (ok)
+ *vp = LookupResult(cx, obj, obj2, prop);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_SET_PROPERTY(cx, obj, (jsid)atom, vp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
+{
+ jsval junk;
+
+ CHECK_REQUEST(cx);
+ return JS_DeleteProperty2(cx, obj, name, &junk);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
+ jsval *rval)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, rval);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefineUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs)
+{
+ CHECK_REQUEST(cx);
+ return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
+ attrs, 0, 0);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ uintN *attrsp, JSBool *foundp)
+{
+ CHECK_REQUEST(cx);
+ return GetPropertyAttributes(cx, obj,
+ js_AtomizeChars(cx, name, AUTO_NAMELEN(name,namelen), 0),
+ attrsp, foundp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ uintN attrs, JSBool *foundp)
+{
+ CHECK_REQUEST(cx);
+ return SetPropertyAttributes(cx, obj,
+ js_AtomizeChars(cx, name, AUTO_NAMELEN(name,namelen), 0),
+ attrs, foundp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ int8 tinyid, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs)
+{
+ CHECK_REQUEST(cx);
+ return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
+ attrs, SPROP_HAS_SHORTID, tinyid);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_LookupUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp)
+{
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
+ if (ok)
+ *vp = LookupResult(cx, obj, obj2, prop);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name,namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name,namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_SET_PROPERTY(cx, obj, (jsid)atom, vp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *rval)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name,namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, rval);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
+{
+ CHECK_REQUEST(cx);
+ /* NB: jsuint cast does ToUint32. */
+ return js_NewArrayObject(cx, (jsuint)length, vector);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsArrayObject(JSContext *cx, JSObject *obj)
+{
+ return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
+{
+ CHECK_REQUEST(cx);
+ return js_GetLengthProperty(cx, obj, lengthp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
+{
+ CHECK_REQUEST(cx);
+ return js_SetLengthProperty(cx, obj, length);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
+{
+ CHECK_REQUEST(cx);
+ return js_HasLengthProperty(cx, obj, lengthp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
+{
+ CHECK_REQUEST(cx);
+ return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(index), value,
+ getter, setter, attrs, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
+{
+ JSObject *obj2;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ if (!LookupProperty(cx, obj, name, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ js_ReportIsNotDefined(cx, name);
+ return JS_FALSE;
+ }
+ if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
+ char numBuf[12];
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
+ numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
+ return JS_FALSE;
+ }
+ sprop = (JSScopeProperty *)prop;
+ ok = (js_AddNativeProperty(cx, obj, INT_TO_JSVAL(alias),
+ sprop->getter, sprop->setter, sprop->slot,
+ sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
+ sprop->shortid)
+ != NULL);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
+{
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSVAL(index), &obj2, &prop);
+ if (ok)
+ *vp = LookupResult(cx, obj, obj2, prop);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
+{
+ CHECK_REQUEST(cx);
+ return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSVAL(index), vp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
+{
+ CHECK_REQUEST(cx);
+ return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSVAL(index), vp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
+{
+ jsval junk;
+
+ CHECK_REQUEST(cx);
+ return JS_DeleteElement2(cx, obj, index, &junk);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
+{
+ CHECK_REQUEST(cx);
+ return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSVAL(index), rval);
+}
+
+JS_PUBLIC_API(void)
+JS_ClearScope(JSContext *cx, JSObject *obj)
+{
+ CHECK_REQUEST(cx);
+
+ if (obj->map->ops->clear)
+ obj->map->ops->clear(cx, obj);
+}
+
+JS_PUBLIC_API(JSIdArray *)
+JS_Enumerate(JSContext *cx, JSObject *obj)
+{
+ jsint i, n;
+ jsval iter_state, num_properties;
+ jsid id;
+ JSIdArray *ida;
+ jsval *vector;
+
+ CHECK_REQUEST(cx);
+
+ ida = NULL;
+ iter_state = JSVAL_NULL;
+
+ /* Get the number of properties to enumerate. */
+ if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
+ goto error;
+ if (!JSVAL_IS_INT(num_properties)) {
+ JS_ASSERT(0);
+ goto error;
+ }
+
+ /* Grow as needed if we don't know the exact amount ahead of time. */
+ n = JSVAL_TO_INT(num_properties);
+ if (n <= 0)
+ n = 8;
+
+ /* Create an array of jsids large enough to hold all the properties */
+ ida = js_NewIdArray(cx, n);
+ if (!ida)
+ goto error;
+
+ i = 0;
+ vector = &ida->vector[0];
+ for (;;) {
+ if (i == ida->length) {
+ /* Grow length by factor of 1.5 instead of doubling. */
+ jsint newlen = ida->length + (((jsuint)ida->length + 1) >> 1);
+ ida = js_GrowIdArray(cx, ida, newlen);
+ if (!ida)
+ goto error;
+ vector = &ida->vector[0];
+ }
+
+ if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
+ goto error;
+
+ /* No more jsid's to enumerate ? */
+ if (iter_state == JSVAL_NULL)
+ break;
+ vector[i++] = id;
+ }
+ ida->length = i;
+ return ida;
+
+error:
+ if (iter_state != JSVAL_NULL)
+ OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
+ if (ida)
+ JS_DestroyIdArray(cx, ida);
+ return NULL;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
+ jsval *vp, uintN *attrsp)
+{
+ CHECK_REQUEST(cx);
+ return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
+}
+
+JS_PUBLIC_API(JSCheckAccessOp)
+JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb)
+{
+ JSCheckAccessOp oldacb;
+
+ oldacb = rt->checkObjectAccess;
+ rt->checkObjectAccess = acb;
+ return oldacb;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
+{
+ JSClass *clasp;
+ uint32 slot;
+
+ CHECK_REQUEST(cx);
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if (index >= JSCLASS_RESERVED_SLOTS(clasp)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_RESERVED_SLOT_RANGE);
+ return JS_FALSE;
+ }
+ slot = JSSLOT_START(clasp) + index;
+ *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
+{
+ JSClass *clasp;
+ uint32 slot;
+
+ CHECK_REQUEST(cx);
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if (index >= JSCLASS_RESERVED_SLOTS(clasp)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_RESERVED_SLOT_RANGE);
+ return JS_FALSE;
+ }
+ slot = JSSLOT_START(clasp) + index;
+ OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
+ return JS_TRUE;
+}
+
+#ifdef JS_THREADSAFE
+JS_PUBLIC_API(jsrefcount)
+JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
+{
+ return JS_ATOMIC_INCREMENT(&principals->refcount);
+}
+
+JS_PUBLIC_API(jsrefcount)
+JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
+{
+ jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
+ if (rc == 0)
+ principals->destroy(cx, principals);
+ return rc;
+}
+#endif
+
+JS_PUBLIC_API(JSPrincipalsTranscoder)
+JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
+{
+ JSPrincipalsTranscoder oldpx;
+
+ oldpx = rt->principalsTranscoder;
+ rt->principalsTranscoder = px;
+ return oldpx;
+}
+
+JS_PUBLIC_API(JSObjectPrincipalsFinder)
+JS_SetObjectPrincipalsFinder(JSContext *cx, JSObjectPrincipalsFinder fop)
+{
+ JSObjectPrincipalsFinder oldfop;
+
+ oldfop = cx->findObjectPrincipals;
+ cx->findObjectPrincipals = fop;
+ return oldfop;
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
+ JSObject *parent, const char *name)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+
+ if (!name) {
+ atom = NULL;
+ } else {
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return NULL;
+ }
+ return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
+{
+ CHECK_REQUEST(cx);
+ if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
+ /* Indicate we cannot clone this object. */
+ return funobj;
+ }
+ return js_CloneFunctionObject(cx, funobj, parent);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetFunctionObject(JSFunction *fun)
+{
+ return fun->object;
+}
+
+JS_PUBLIC_API(const char *)
+JS_GetFunctionName(JSFunction *fun)
+{
+ return fun->atom
+ ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
+ : js_anonymous_str;
+}
+
+JS_PUBLIC_API(JSString *)
+JS_GetFunctionId(JSFunction *fun)
+{
+ return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
+}
+
+JS_PUBLIC_API(uintN)
+JS_GetFunctionFlags(JSFunction *fun)
+{
+ return fun->flags;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
+{
+ return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
+{
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ for (; fs->name; fs++) {
+ fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs,
+ fs->flags);
+ if (!fun)
+ return JS_FALSE;
+ fun->extra = fs->extra;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
+ uintN nargs, uintN attrs)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return NULL;
+ return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
+}
+
+static JSScript *
+CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
+ void *tempMark, JSBool *eofp)
+{
+ JSBool eof;
+ JSArenaPool codePool, notePool;
+ JSCodeGenerator cg;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ eof = JS_FALSE;
+ JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
+ JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));
+ if (!js_InitCodeGenerator(cx, &cg, &codePool, &notePool,
+ ts->filename, ts->lineno,
+ ts->principals)) {
+ script = NULL;
+ } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
+ script = NULL;
+ eof = (ts->flags & TSF_EOF) != 0;
+ } else {
+ script = js_NewScriptFromCG(cx, &cg, NULL);
+ }
+ if (eofp)
+ *eofp = eof;
+ if (!js_CloseTokenStream(cx, ts)) {
+ if (script)
+ js_DestroyScript(cx, script);
+ script = NULL;
+ }
+ cg.tempMark = tempMark;
+ js_FinishCodeGenerator(cx, &cg);
+ JS_FinishArenaPool(&codePool);
+ JS_FinishArenaPool(&notePool);
+ return script;
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_CompileScript(JSContext *cx, JSObject *obj,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+{
+ jschar *chars;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
+ JS_free(cx, chars);
+ return script;
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+{
+ jschar *chars;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
+ chars, length, filename, lineno);
+ JS_free(cx, chars);
+ return script;
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_CompileUCScript(JSContext *cx, JSObject *obj,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+{
+ CHECK_REQUEST(cx);
+ return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
+ filename, lineno);
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+{
+ void *mark;
+ JSTokenStream *ts;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
+ if (!ts)
+ return NULL;
+ script = CompileTokenStream(cx, obj, ts, mark, NULL);
+#if JS_HAS_EXCEPTIONS
+ if (!script && !cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return script;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
+ const char *bytes, size_t length)
+{
+ jschar *chars;
+ JSBool result;
+ JSExceptionState *exnState;
+ void *tempMark;
+ JSTokenStream *ts;
+ JSErrorReporter older;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return JS_TRUE;
+
+ /*
+ * Return true on any out-of-memory error, so our caller doesn't try to
+ * collect more buffered source.
+ */
+ result = JS_TRUE;
+ exnState = JS_SaveExceptionState(cx);
+ tempMark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
+ if (ts) {
+ older = JS_SetErrorReporter(cx, NULL);
+ if (!js_ParseTokenStream(cx, obj, ts)) {
+ /*
+ * We ran into an error. If it was because we ran out of source,
+ * we return false, so our caller will know to try to collect more
+ * buffered source.
+ */
+ result = (ts->flags & TSF_EOF) == 0;
+ }
+
+ JS_SetErrorReporter(cx, older);
+ js_CloseTokenStream(cx, ts);
+ JS_ARENA_RELEASE(&cx->tempPool, tempMark);
+ }
+
+ JS_free(cx, chars);
+ JS_RestoreExceptionState(cx, exnState);
+ return result;
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
+{
+ void *mark;
+ JSTokenStream *ts;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewFileTokenStream(cx, filename, stdin);
+ if (!ts)
+ return NULL;
+ script = CompileTokenStream(cx, obj, ts, mark, NULL);
+#if JS_HAS_EXCEPTIONS
+ if (!script && !cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return script;
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
+ FILE *file)
+{
+ return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
+ const char *filename, FILE *file,
+ JSPrincipals *principals)
+{
+ void *mark;
+ JSTokenStream *ts;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewFileTokenStream(cx, NULL, file);
+ if (!ts)
+ return NULL;
+ ts->filename = filename;
+ /* XXXshaver js_NewFileTokenStream should do this, because it drops */
+ if (principals) {
+ ts->principals = principals;
+ JSPRINCIPALS_HOLD(cx, ts->principals);
+ }
+ script = CompileTokenStream(cx, obj, ts, mark, NULL);
+#if JS_HAS_EXCEPTIONS
+ if (!script && !cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return script;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_NewScriptObject(JSContext *cx, JSScript *script)
+{
+ JSObject *obj;
+
+ /*
+ * We use a dummy stack frame to protect the script from a GC caused
+ * by debugger-hook execution.
+ *
+ * XXX We really need a way to manage local roots and such more
+ * XXX automatically, at which point we can remove this one-off hack
+ * XXX and others within the engine. See bug 40757 for discussion.
+ */
+ JSStackFrame dummy;
+
+ CHECK_REQUEST(cx);
+
+ memset(&dummy, 0, sizeof dummy);
+ dummy.down = cx->fp;
+ dummy.script = script;
+ cx->fp = &dummy;
+
+ obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
+
+ cx->fp = dummy.down;
+ if (!obj)
+ return NULL;
+
+ if (script) {
+ if (!JS_SetPrivate(cx, obj, script))
+ return NULL;
+ script->object = obj;
+ }
+ return obj;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetScriptObject(JSScript *script)
+{
+ return script->object;
+}
+
+JS_PUBLIC_API(void)
+JS_DestroyScript(JSContext *cx, JSScript *script)
+{
+ CHECK_REQUEST(cx);
+ js_DestroyScript(cx, script);
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
+ uintN nargs, const char **argnames,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+{
+ jschar *chars;
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
+ filename, lineno);
+ JS_free(cx, chars);
+ return fun;
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals, const char *name,
+ uintN nargs, const char **argnames,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+{
+ jschar *chars;
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
+ nargs, argnames, chars, length,
+ filename, lineno);
+ JS_free(cx, chars);
+ return fun;
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
+ uintN nargs, const char **argnames,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+{
+ CHECK_REQUEST(cx);
+ return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
+ nargs, argnames,
+ chars, length,
+ filename, lineno);
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals, const char *name,
+ uintN nargs, const char **argnames,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+{
+ void *mark;
+ JSTokenStream *ts;
+ JSFunction *fun;
+ JSAtom *funAtom, *argAtom;
+ uintN i;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
+ if (!ts) {
+ fun = NULL;
+ goto out;
+ }
+ if (!name) {
+ funAtom = NULL;
+ } else {
+ funAtom = js_Atomize(cx, name, strlen(name), 0);
+ if (!funAtom) {
+ fun = NULL;
+ goto out;
+ }
+ }
+ fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
+ if (!fun)
+ goto out;
+ if (nargs) {
+ for (i = 0; i < nargs; i++) {
+ argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
+ if (!argAtom)
+ break;
+ if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
+ js_GetArgument, js_SetArgument,
+ SPROP_INVALID_SLOT,
+ JSPROP_ENUMERATE | JSPROP_PERMANENT |
+ JSPROP_SHARED,
+ SPROP_HAS_SHORTID, i)) {
+ break;
+ }
+ }
+ if (i < nargs) {
+ fun = NULL;
+ goto out;
+ }
+ }
+ if (!js_CompileFunctionBody(cx, ts, fun)) {
+ fun = NULL;
+ goto out;
+ }
+ if (obj && funAtom) {
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)funAtom,
+ OBJECT_TO_JSVAL(fun->object),
+ NULL, NULL, 0, NULL)) {
+ return NULL;
+ }
+ }
+out:
+ if (ts)
+ js_CloseTokenStream(cx, ts);
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+#if JS_HAS_EXCEPTIONS
+ if (!fun && !cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return fun;
+}
+
+JS_PUBLIC_API(JSString *)
+JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
+ uintN indent)
+{
+ JSPrinter *jp;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ jp = js_NewPrinter(cx, name,
+ indent & ~JS_DONT_PRETTY_PRINT,
+ !(indent & JS_DONT_PRETTY_PRINT));
+ if (!jp)
+ return NULL;
+ if (js_DecompileScript(jp, script))
+ str = js_GetPrinterOutput(jp);
+ else
+ str = NULL;
+ js_DestroyPrinter(jp);
+ return str;
+}
+
+JS_PUBLIC_API(JSString *)
+JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
+{
+ JSPrinter *jp;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
+ indent & ~JS_DONT_PRETTY_PRINT,
+ !(indent & JS_DONT_PRETTY_PRINT));
+ if (!jp)
+ return NULL;
+ if (js_DecompileFunction(jp, fun))
+ str = js_GetPrinterOutput(jp);
+ else
+ str = NULL;
+ js_DestroyPrinter(jp);
+ return str;
+}
+
+JS_PUBLIC_API(JSString *)
+JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
+{
+ JSPrinter *jp;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
+ indent & ~JS_DONT_PRETTY_PRINT,
+ !(indent & JS_DONT_PRETTY_PRINT));
+ if (!jp)
+ return NULL;
+ if (js_DecompileFunctionBody(jp, fun))
+ str = js_GetPrinterOutput(jp);
+ else
+ str = NULL;
+ js_DestroyPrinter(jp);
+ return str;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
+{
+ CHECK_REQUEST(cx);
+ if (!js_Execute(cx, obj, script, NULL, 0, rval)) {
+#if JS_HAS_EXCEPTIONS
+ if (!cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
+ JSExecPart part, jsval *rval)
+{
+ JSScript tmp;
+ JSRuntime *rt;
+ JSBool ok;
+
+ /* Make a temporary copy of the JSScript structure and farble it a bit. */
+ tmp = *script;
+ if (part == JSEXEC_PROLOG) {
+ tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
+ } else {
+ tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
+ tmp.code = tmp.main;
+ }
+
+ /* Tell the debugger about our temporary copy of the script structure. */
+ rt = cx->runtime;
+ if (rt->newScriptHook) {
+ rt->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
+ rt->newScriptHookData);
+ }
+
+ /* Execute the farbled struct and tell the debugger to forget about it. */
+ ok = JS_ExecuteScript(cx, obj, &tmp, rval);
+ if (rt->destroyScriptHook)
+ rt->destroyScriptHook(cx, &tmp, rt->destroyScriptHookData);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_EvaluateScript(JSContext *cx, JSObject *obj,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+{
+ jschar *chars;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return JS_FALSE;
+ ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
+ JS_free(cx, chars);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+{
+ jschar *chars;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return JS_FALSE;
+ ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
+ filename, lineno, rval);
+ JS_free(cx, chars);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
+ const jschar *chars, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+{
+ CHECK_REQUEST(cx);
+ return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
+ filename, lineno, rval);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const jschar *chars, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+{
+ JSScript *script;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
+ filename, lineno);
+ if (!script)
+ return JS_FALSE;
+ ok = js_Execute(cx, obj, script, NULL, 0, rval);
+#if JS_HAS_EXCEPTIONS
+ if (!ok && !cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ JS_DestroyScript(cx, script);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ CHECK_REQUEST(cx);
+ if (!js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
+ rval)) {
+#if JS_HAS_EXCEPTIONS
+ if (!cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ jsval fval;
+
+ CHECK_REQUEST(cx);
+ if (!JS_GetProperty(cx, obj, name, &fval))
+ return JS_FALSE;
+ if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) {
+#if JS_HAS_EXCEPTIONS
+ if (!cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ CHECK_REQUEST(cx);
+ if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) {
+#if JS_HAS_EXCEPTIONS
+ if (!cx->fp)
+ js_ReportUncaughtException(cx);
+#endif
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBranchCallback)
+JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
+{
+ JSBranchCallback oldcb;
+
+ oldcb = cx->branchCallback;
+ cx->branchCallback = cb;
+ return oldcb;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsRunning(JSContext *cx)
+{
+ return cx->fp != NULL;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsConstructing(JSContext *cx)
+{
+ return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
+}
+
+JS_FRIEND_API(JSBool)
+JS_IsAssigning(JSContext *cx)
+{
+ JSStackFrame *fp;
+ jsbytecode *pc;
+
+ for (fp = cx->fp; fp && !fp->script; fp = fp->down)
+ continue;
+ if (!fp || !(pc = fp->pc))
+ return JS_FALSE;
+ return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
+}
+
+JS_PUBLIC_API(void)
+JS_SetCallReturnValue2(JSContext *cx, jsval v)
+{
+#if JS_HAS_LVALUE_RETURN
+ cx->rval2 = v;
+ cx->rval2set = JS_TRUE;
+#endif
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(JSString *)
+JS_NewString(JSContext *cx, char *bytes, size_t length)
+{
+ jschar *chars;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ /* Make a Unicode vector from the 8-bit char codes in bytes. */
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+
+ /* Free chars (but not bytes, which caller frees on error) if we fail. */
+ str = js_NewString(cx, chars, length, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ return NULL;
+ }
+
+ /* Hand off bytes to the deflated string cache, if possible. */
+ if (!js_SetStringBytes(str, bytes, length))
+ JS_free(cx, bytes);
+ return str;
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
+{
+ jschar *js;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ js = js_InflateString(cx, s, n);
+ if (!js)
+ return NULL;
+ str = js_NewString(cx, js, n, 0);
+ if (!str)
+ JS_free(cx, js);
+ return str;
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewStringCopyZ(JSContext *cx, const char *s)
+{
+ size_t n;
+ jschar *js;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ if (!s)
+ return cx->runtime->emptyString;
+ n = strlen(s);
+ js = js_InflateString(cx, s, n);
+ if (!js)
+ return NULL;
+ str = js_NewString(cx, js, n, 0);
+ if (!str)
+ JS_free(cx, js);
+ return str;
+}
+
+JS_PUBLIC_API(JSString *)
+JS_InternString(JSContext *cx, const char *s)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
+ if (!atom)
+ return NULL;
+ return ATOM_TO_STRING(atom);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
+{
+ CHECK_REQUEST(cx);
+ return js_NewString(cx, chars, length, 0);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
+{
+ CHECK_REQUEST(cx);
+ return js_NewStringCopyN(cx, s, n, 0);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
+{
+ CHECK_REQUEST(cx);
+ if (!s)
+ return cx->runtime->emptyString;
+ return js_NewStringCopyZ(cx, s, 0);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
+{
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
+ if (!atom)
+ return NULL;
+ return ATOM_TO_STRING(atom);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_InternUCString(JSContext *cx, const jschar *s)
+{
+ return JS_InternUCStringN(cx, s, js_strlen(s));
+}
+
+JS_PUBLIC_API(char *)
+JS_GetStringBytes(JSString *str)
+{
+ char *bytes;
+
+ bytes = js_GetStringBytes(str);
+ return bytes ? bytes : "";
+}
+
+JS_PUBLIC_API(jschar *)
+JS_GetStringChars(JSString *str)
+{
+ /*
+ * API botch (again, shades of JS_GetStringBytes): we have no cx to pass
+ * to js_UndependString (called by js_GetStringChars) for out-of-memory
+ * error reports, so js_UndependString passes NULL and suppresses errors.
+ * If it fails to convert a dependent string into an independent one, our
+ * caller will not be guaranteed a \u0000 terminator as a backstop. This
+ * may break some clients who already misbehave on embedded NULs.
+ *
+ * The gain of dependent strings, which cure quadratic and cubic growth
+ * rate bugs in string concatenation, is worth this slight loss in API
+ * compatibility.
+ */
+ jschar *chars;
+
+ chars = js_GetStringChars(str);
+ return chars ? chars : JSSTRING_CHARS(str);
+}
+
+JS_PUBLIC_API(size_t)
+JS_GetStringLength(JSString *str)
+{
+ return JSSTRING_LENGTH(str);
+}
+
+JS_PUBLIC_API(intN)
+JS_CompareStrings(JSString *str1, JSString *str2)
+{
+ return js_CompareStrings(str1, str2);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
+{
+ CHECK_REQUEST(cx);
+ return js_NewString(cx, chars, length, GCF_MUTABLE);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
+ size_t length)
+{
+ CHECK_REQUEST(cx);
+ return js_NewDependentString(cx, str, start, length, 0);
+}
+
+JS_PUBLIC_API(JSString *)
+JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
+{
+ CHECK_REQUEST(cx);
+ return js_ConcatStrings(cx, left, right);
+}
+
+JS_PUBLIC_API(const jschar *)
+JS_UndependString(JSContext *cx, JSString *str)
+{
+ CHECK_REQUEST(cx);
+ return js_UndependString(cx, str);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_MakeStringImmutable(JSContext *cx, JSString *str)
+{
+ CHECK_REQUEST(cx);
+ if (!js_UndependString(cx, str))
+ return JS_FALSE;
+
+ *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
+ return JS_TRUE;
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(void)
+JS_ReportError(JSContext *cx, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
+ va_end(ap);
+}
+
+JS_PUBLIC_API(void)
+JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
+ void *userRef, const uintN errorNumber, ...)
+{
+ va_list ap;
+
+ va_start(ap, errorNumber);
+ js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
+ errorNumber, JS_TRUE, ap);
+ va_end(ap);
+}
+
+JS_PUBLIC_API(void)
+JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
+ void *userRef, const uintN errorNumber, ...)
+{
+ va_list ap;
+
+ va_start(ap, errorNumber);
+ js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
+ errorNumber, JS_FALSE, ap);
+ va_end(ap);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ReportWarning(JSContext *cx, const char *format, ...)
+{
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, format);
+ ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
+ va_end(ap);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
+ JSErrorCallback errorCallback, void *userRef,
+ const uintN errorNumber, ...)
+{
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, errorNumber);
+ ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
+ errorNumber, JS_TRUE, ap);
+ va_end(ap);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
+ JSErrorCallback errorCallback, void *userRef,
+ const uintN errorNumber, ...)
+{
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, errorNumber);
+ ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
+ errorNumber, JS_FALSE, ap);
+ va_end(ap);
+ return ok;
+}
+
+JS_PUBLIC_API(void)
+JS_ReportOutOfMemory(JSContext *cx)
+{
+ js_ReportOutOfMemory(cx, js_GetErrorMessage);
+}
+
+JS_PUBLIC_API(JSErrorReporter)
+JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
+{
+ JSErrorReporter older;
+
+ older = cx->errorReporter;
+ cx->errorReporter = er;
+ return older;
+}
+
+/************************************************************************/
+
+/*
+ * Regular Expressions.
+ */
+JS_PUBLIC_API(JSObject *)
+JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
+{
+#if JS_HAS_REGEXPS
+ jschar *chars;
+ JSObject *obj;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
+ JS_free(cx, chars);
+ return obj;
+#else
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
+ return NULL;
+#endif
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
+{
+ CHECK_REQUEST(cx);
+#if JS_HAS_REGEXPS
+ return js_NewRegExpObject(cx, NULL, chars, length, flags);
+#else
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
+ return NULL;
+#endif
+}
+
+JS_PUBLIC_API(void)
+JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
+{
+ JSRegExpStatics *res;
+
+ CHECK_REQUEST(cx);
+ /* No locking required, cx is thread-private and input must be live. */
+ res = &cx->regExpStatics;
+ res->input = input;
+ res->multiline = multiline;
+ cx->runtime->gcPoke = JS_TRUE;
+}
+
+JS_PUBLIC_API(void)
+JS_ClearRegExpStatics(JSContext *cx)
+{
+ JSRegExpStatics *res;
+
+ /* No locking required, cx is thread-private and input must be live. */
+ res = &cx->regExpStatics;
+ res->input = NULL;
+ res->multiline = JS_FALSE;
+ res->parenCount = 0;
+ res->lastMatch = res->lastParen = js_EmptySubString;
+ res->leftContext = res->rightContext = js_EmptySubString;
+ cx->runtime->gcPoke = JS_TRUE;
+}
+
+JS_PUBLIC_API(void)
+JS_ClearRegExpRoots(JSContext *cx)
+{
+ JSRegExpStatics *res;
+
+ /* No locking required, cx is thread-private and input must be live. */
+ res = &cx->regExpStatics;
+ res->input = NULL;
+ cx->runtime->gcPoke = JS_TRUE;
+}
+
+/* TODO: compile, execute, get/set other statics... */
+
+/************************************************************************/
+
+JS_PUBLIC_API(void)
+JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
+{
+ cx->localeCallbacks = callbacks;
+}
+
+JS_PUBLIC_API(JSLocaleCallbacks *)
+JS_GetLocaleCallbacks(JSContext *cx)
+{
+ return cx->localeCallbacks;
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(JSBool)
+JS_IsExceptionPending(JSContext *cx)
+{
+#if JS_HAS_EXCEPTIONS
+ return (JSBool) cx->throwing;
+#else
+ return JS_FALSE;
+#endif
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetPendingException(JSContext *cx, jsval *vp)
+{
+#if JS_HAS_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ if (!cx->throwing)
+ return JS_FALSE;
+ *vp = cx->exception;
+ return JS_TRUE;
+#else
+ return JS_FALSE;
+#endif
+}
+
+JS_PUBLIC_API(void)
+JS_SetPendingException(JSContext *cx, jsval v)
+{
+ CHECK_REQUEST(cx);
+#if JS_HAS_EXCEPTIONS
+ cx->throwing = JS_TRUE;
+ cx->exception = v;
+#endif
+}
+
+JS_PUBLIC_API(void)
+JS_ClearPendingException(JSContext *cx)
+{
+#if JS_HAS_EXCEPTIONS
+ cx->throwing = JS_FALSE;
+ cx->exception = JSVAL_VOID;
+#endif
+}
+
+#if JS_HAS_EXCEPTIONS
+struct JSExceptionState {
+ JSBool throwing;
+ jsval exception;
+};
+#endif
+
+JS_PUBLIC_API(JSExceptionState *)
+JS_SaveExceptionState(JSContext *cx)
+{
+#if JS_HAS_EXCEPTIONS
+ JSExceptionState *state;
+
+ CHECK_REQUEST(cx);
+ state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
+ if (state) {
+ state->throwing = JS_GetPendingException(cx, &state->exception);
+ if (state->throwing && JSVAL_IS_GCTHING(state->exception))
+ js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
+ }
+ return state;
+#else
+ return NULL;
+#endif
+}
+
+JS_PUBLIC_API(void)
+JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
+{
+#if JS_HAS_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ if (state) {
+ if (state->throwing)
+ JS_SetPendingException(cx, state->exception);
+ else
+ JS_ClearPendingException(cx);
+ JS_DropExceptionState(cx, state);
+ }
+#endif
+}
+
+JS_PUBLIC_API(void)
+JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
+{
+#if JS_HAS_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ if (state) {
+ if (state->throwing && JSVAL_IS_GCTHING(state->exception))
+ JS_RemoveRoot(cx, &state->exception);
+ JS_free(cx, state);
+ }
+#endif
+}
+
+JS_PUBLIC_API(JSErrorReport *)
+JS_ErrorFromException(JSContext *cx, jsval v)
+{
+#if JS_HAS_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ return js_ErrorFromException(cx, v);
+#else
+ return NULL;
+#endif
+}
+
+#ifdef JS_THREADSAFE
+JS_PUBLIC_API(jsword)
+JS_GetContextThread(JSContext *cx)
+{
+ return cx->thread;
+}
+
+JS_PUBLIC_API(jsword)
+JS_SetContextThread(JSContext *cx)
+{
+ intN old = cx->thread;
+ cx->thread = js_CurrentThreadId();
+ return old;
+}
+
+JS_PUBLIC_API(intN)
+JS_ClearContextThread(JSContext *cx)
+{
+ intN old = cx->thread;
+ cx->thread = 0;
+ return old;
+}
+#endif
+
+/************************************************************************/
+
+#if defined(XP_WIN)
+#include <windows.h>
+/*
+ * Initialization routine for the JS DLL...
+ */
+
+/*
+ * Global Instance handle...
+ * In Win32 this is the module handle of the DLL.
+ *
+ * In Win16 this is the instance handle of the application
+ * which loaded the DLL.
+ */
+
+#ifdef _WIN32
+BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
+{
+ return TRUE;
+}
+
+#else /* !_WIN32 */
+
+int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
+ WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ return TRUE;
+}
+
+BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
+{
+ return TRUE;
+}
+
+#endif /* !_WIN32 */
+#endif /* XP_WIN */
diff --git a/src/dom/js/jsapi.h b/src/dom/js/jsapi.h
new file mode 100644
index 000000000..92b4e1d59
--- /dev/null
+++ b/src/dom/js/jsapi.h
@@ -0,0 +1,1752 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsapi_h___
+#define jsapi_h___
+/*
+ * JavaScript API.
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * Type tags stored in the low bits of a jsval.
+ */
+#define JSVAL_OBJECT 0x0 /* untagged reference to object */
+#define JSVAL_INT 0x1 /* tagged 31-bit integer value */
+#define JSVAL_DOUBLE 0x2 /* tagged reference to double */
+#define JSVAL_STRING 0x4 /* tagged reference to string */
+#define JSVAL_BOOLEAN 0x6 /* tagged boolean value */
+
+/* Type tag bitfield length and derived macros. */
+#define JSVAL_TAGBITS 3
+#define JSVAL_TAGMASK JS_BITMASK(JSVAL_TAGBITS)
+#define JSVAL_TAG(v) ((v) & JSVAL_TAGMASK)
+#define JSVAL_SETTAG(v,t) ((v) | (t))
+#define JSVAL_CLRTAG(v) ((v) & ~(jsval)JSVAL_TAGMASK)
+#define JSVAL_ALIGN JS_BIT(JSVAL_TAGBITS)
+
+/* Predicates for type testing. */
+#define JSVAL_IS_OBJECT(v) (JSVAL_TAG(v) == JSVAL_OBJECT)
+#define JSVAL_IS_NUMBER(v) (JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v))
+#define JSVAL_IS_INT(v) (((v) & JSVAL_INT) && (v) != JSVAL_VOID)
+#define JSVAL_IS_DOUBLE(v) (JSVAL_TAG(v) == JSVAL_DOUBLE)
+#define JSVAL_IS_STRING(v) (JSVAL_TAG(v) == JSVAL_STRING)
+#define JSVAL_IS_BOOLEAN(v) (JSVAL_TAG(v) == JSVAL_BOOLEAN)
+#define JSVAL_IS_NULL(v) ((v) == JSVAL_NULL)
+#define JSVAL_IS_VOID(v) ((v) == JSVAL_VOID)
+#define JSVAL_IS_PRIMITIVE(v) (!JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v))
+
+/* Objects, strings, and doubles are GC'ed. */
+#define JSVAL_IS_GCTHING(v) (!((v) & JSVAL_INT) && !JSVAL_IS_BOOLEAN(v))
+#define JSVAL_TO_GCTHING(v) ((void *)JSVAL_CLRTAG(v))
+#define JSVAL_TO_OBJECT(v) ((JSObject *)JSVAL_TO_GCTHING(v))
+#define JSVAL_TO_DOUBLE(v) ((jsdouble *)JSVAL_TO_GCTHING(v))
+#define JSVAL_TO_STRING(v) ((JSString *)JSVAL_TO_GCTHING(v))
+#define OBJECT_TO_JSVAL(obj) ((jsval)(obj))
+#define DOUBLE_TO_JSVAL(dp) JSVAL_SETTAG((jsval)(dp), JSVAL_DOUBLE)
+#define STRING_TO_JSVAL(str) JSVAL_SETTAG((jsval)(str), JSVAL_STRING)
+
+/* Lock and unlock the GC thing held by a jsval. */
+#define JSVAL_LOCK(cx,v) (JSVAL_IS_GCTHING(v) \
+ ? JS_LockGCThing(cx, JSVAL_TO_GCTHING(v)) \
+ : JS_TRUE)
+#define JSVAL_UNLOCK(cx,v) (JSVAL_IS_GCTHING(v) \
+ ? JS_UnlockGCThing(cx, JSVAL_TO_GCTHING(v)) \
+ : JS_TRUE)
+
+/* Domain limits for the jsval int type. */
+#define JSVAL_INT_BITS 31
+#define JSVAL_INT_POW2(n) ((jsval)1 << (n))
+#define JSVAL_INT_MIN ((jsval)1 - JSVAL_INT_POW2(30))
+#define JSVAL_INT_MAX (JSVAL_INT_POW2(30) - 1)
+#define INT_FITS_IN_JSVAL(i) ((jsuint)((i)+JSVAL_INT_MAX) <= 2*JSVAL_INT_MAX)
+#define JSVAL_TO_INT(v) ((jsint)(v) >> 1)
+#define INT_TO_JSVAL(i) (((jsval)(i) << 1) | JSVAL_INT)
+
+/* Convert between boolean and jsval. */
+#define JSVAL_TO_BOOLEAN(v) ((JSBool)((v) >> JSVAL_TAGBITS))
+#define BOOLEAN_TO_JSVAL(b) JSVAL_SETTAG((jsval)(b) << JSVAL_TAGBITS, \
+ JSVAL_BOOLEAN)
+
+/* A private data pointer (2-byte-aligned) can be stored as an int jsval. */
+#define JSVAL_TO_PRIVATE(v) ((void *)((v) & ~JSVAL_INT))
+#define PRIVATE_TO_JSVAL(p) ((jsval)(p) | JSVAL_INT)
+
+/* Property attributes, set in JSPropertySpec and passed to API functions. */
+#define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */
+#define JSPROP_READONLY 0x02 /* not settable: assignment is no-op */
+#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */
+#define JSPROP_EXPORTED 0x08 /* property is exported from object */
+#define JSPROP_GETTER 0x10 /* property holds getter function */
+#define JSPROP_SETTER 0x20 /* property holds setter function */
+#define JSPROP_SHARED 0x40 /* don't allocate a value slot for this
+ property; don't copy the property on
+ set of the same-named property in an
+ object that delegates to a prototype
+ containing this property */
+#define JSPROP_INDEX 0x80 /* name is actually (jsint) index */
+
+/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */
+#define JSFUN_LAMBDA 0x08 /* expressed, not declared, function */
+#define JSFUN_GETTER JSPROP_GETTER
+#define JSFUN_SETTER JSPROP_SETTER
+#define JSFUN_BOUND_METHOD 0x40 /* bind this to fun->object's parent */
+#define JSFUN_HEAVYWEIGHT 0x80 /* activation requires a Call object */
+#define JSFUN_FLAGS_MASK 0xf8 /* overlay JSFUN_* attributes */
+
+/*
+ * Well-known JS values. The extern'd variables are initialized when the
+ * first JSContext is created by JS_NewContext (see below).
+ */
+#define JSVAL_VOID INT_TO_JSVAL(0 - JSVAL_INT_POW2(30))
+#define JSVAL_NULL OBJECT_TO_JSVAL(0)
+#define JSVAL_ZERO INT_TO_JSVAL(0)
+#define JSVAL_ONE INT_TO_JSVAL(1)
+#define JSVAL_FALSE BOOLEAN_TO_JSVAL(JS_FALSE)
+#define JSVAL_TRUE BOOLEAN_TO_JSVAL(JS_TRUE)
+
+/*
+ * Microseconds since the epoch, midnight, January 1, 1970 UTC. See the
+ * comment in jstypes.h regarding safe int64 usage.
+ */
+extern JS_PUBLIC_API(int64)
+JS_Now();
+
+/* Don't want to export data, so provide accessors for non-inline jsvals. */
+extern JS_PUBLIC_API(jsval)
+JS_GetNaNValue(JSContext *cx);
+
+extern JS_PUBLIC_API(jsval)
+JS_GetNegativeInfinityValue(JSContext *cx);
+
+extern JS_PUBLIC_API(jsval)
+JS_GetPositiveInfinityValue(JSContext *cx);
+
+extern JS_PUBLIC_API(jsval)
+JS_GetEmptyStringValue(JSContext *cx);
+
+/*
+ * Format is a string of the following characters (spaces are insignificant),
+ * specifying the tabulated type conversions:
+ *
+ * b JSBool Boolean
+ * c uint16/jschar ECMA uint16, Unicode char
+ * i int32 ECMA int32
+ * u uint32 ECMA uint32
+ * j int32 Rounded int32 (coordinate)
+ * d jsdouble IEEE double
+ * I jsdouble Integral IEEE double
+ * s char * C string
+ * S JSString * Unicode string, accessed by a JSString pointer
+ * W jschar * Unicode character vector, 0-terminated (W for wide)
+ * o JSObject * Object reference
+ * f JSFunction * Function private
+ * v jsval Argument value (no conversion)
+ * * N/A Skip this argument (no vararg)
+ * / N/A End of required arguments
+ *
+ * The variable argument list after format must consist of &b, &c, &s, e.g.,
+ * where those variables have the types given above. For the pointer types
+ * char *, JSString *, and JSObject *, the pointed-at memory returned belongs
+ * to the JS runtime, not to the calling native code. The runtime promises
+ * to keep this memory valid so long as argv refers to allocated stack space
+ * (so long as the native function is active).
+ *
+ * Fewer arguments than format specifies may be passed only if there is a /
+ * in format after the last required argument specifier and argc is at least
+ * the number of required arguments. More arguments than format specifies
+ * may be passed without error; it is up to the caller to deal with trailing
+ * unconverted arguments.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
+ ...);
+
+#ifdef va_start
+extern JS_PUBLIC_API(JSBool)
+JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
+ const char *format, va_list ap);
+#endif
+
+/*
+ * Inverse of JS_ConvertArguments: scan format and convert trailing arguments
+ * into jsvals, GC-rooted if necessary by the JS stack. Return null on error,
+ * and a pointer to the new argument vector on success. Also return a stack
+ * mark on success via *markp, in which case the caller must eventually clean
+ * up by calling JS_PopArguments.
+ *
+ * Note that the number of actual arguments supplied is specified exclusively
+ * by format, so there is no argc parameter.
+ */
+extern JS_PUBLIC_API(jsval *)
+JS_PushArguments(JSContext *cx, void **markp, const char *format, ...);
+
+#ifdef va_start
+extern JS_PUBLIC_API(jsval *)
+JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap);
+#endif
+
+extern JS_PUBLIC_API(void)
+JS_PopArguments(JSContext *cx, void *mark);
+
+#ifdef JS_ARGUMENT_FORMATTER_DEFINED
+
+/*
+ * Add and remove a format string handler for JS_{Convert,Push}Arguments{,VA}.
+ * The handler function has this signature (see jspubtd.h):
+ *
+ * JSBool MyArgumentFormatter(JSContext *cx, const char *format,
+ * JSBool fromJS, jsval **vpp, va_list *app);
+ *
+ * It should return true on success, and return false after reporting an error
+ * or detecting an already-reported error.
+ *
+ * For a given format string, for example "AA", the formatter is called from
+ * JS_ConvertArgumentsVA like so:
+ *
+ * formatter(cx, "AA...", JS_TRUE, &sp, &ap);
+ *
+ * sp points into the arguments array on the JS stack, while ap points into
+ * the stdarg.h va_list on the C stack. The JS_TRUE passed for fromJS tells
+ * the formatter to convert zero or more jsvals at sp to zero or more C values
+ * accessed via pointers-to-values at ap, updating both sp (via *vpp) and ap
+ * (via *app) to point past the converted arguments and their result pointers
+ * on the C stack.
+ *
+ * When called from JS_PushArgumentsVA, the formatter is invoked thus:
+ *
+ * formatter(cx, "AA...", JS_FALSE, &sp, &ap);
+ *
+ * where JS_FALSE for fromJS means to wrap the C values at ap according to the
+ * format specifier and store them at sp, updating ap and sp appropriately.
+ *
+ * The "..." after "AA" is the rest of the format string that was passed into
+ * JS_{Convert,Push}Arguments{,VA}. The actual format trailing substring used
+ * in each Convert or PushArguments call is passed to the formatter, so that
+ * one such function may implement several formats, in order to share code.
+ *
+ * Remove just forgets about any handler associated with format. Add does not
+ * copy format, it points at the string storage allocated by the caller, which
+ * is typically a string constant. If format is in dynamic storage, it is up
+ * to the caller to keep the string alive until Remove is called.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_AddArgumentFormatter(JSContext *cx, const char *format,
+ JSArgumentFormatter formatter);
+
+extern JS_PUBLIC_API(void)
+JS_RemoveArgumentFormatter(JSContext *cx, const char *format);
+
+#endif /* JS_ARGUMENT_FORMATTER_DEFINED */
+
+extern JS_PUBLIC_API(JSBool)
+JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_ValueToFunction(JSContext *cx, jsval v);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_ValueToConstructor(JSContext *cx, jsval v);
+
+extern JS_PUBLIC_API(JSString *)
+JS_ValueToString(JSContext *cx, jsval v);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp);
+
+/*
+ * Convert a value to a number, then to an int32, according to the ECMA rules
+ * for ToInt32.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip);
+
+/*
+ * Convert a value to a number, then to a uint32, according to the ECMA rules
+ * for ToUint32.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip);
+
+/*
+ * Convert a value to a number, then to an int32 if it fits by rounding to
+ * nearest; but failing with an error report if the double is out of range
+ * or unordered.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip);
+
+/*
+ * ECMA ToUint16, for mapping a jsval to a Unicode point.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp);
+
+extern JS_PUBLIC_API(JSType)
+JS_TypeOfValue(JSContext *cx, jsval v);
+
+extern JS_PUBLIC_API(const char *)
+JS_GetTypeName(JSContext *cx, JSType type);
+
+/************************************************************************/
+
+/*
+ * Initialization, locking, contexts, and memory allocation.
+ */
+#define JS_NewRuntime JS_Init
+#define JS_DestroyRuntime JS_Finish
+#define JS_LockRuntime JS_Lock
+#define JS_UnlockRuntime JS_Unlock
+
+extern JS_PUBLIC_API(JSRuntime *)
+JS_NewRuntime(uint32 maxbytes);
+
+extern JS_PUBLIC_API(void)
+JS_DestroyRuntime(JSRuntime *rt);
+
+extern JS_PUBLIC_API(void)
+JS_ShutDown(void);
+
+JS_PUBLIC_API(void *)
+JS_GetRuntimePrivate(JSRuntime *rt);
+
+JS_PUBLIC_API(void)
+JS_SetRuntimePrivate(JSRuntime *rt, void *data);
+
+#ifdef JS_THREADSAFE
+
+extern JS_PUBLIC_API(void)
+JS_BeginRequest(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_EndRequest(JSContext *cx);
+
+/* Yield to pending GC operations, regardless of request depth */
+extern JS_PUBLIC_API(void)
+JS_YieldRequest(JSContext *cx);
+
+extern JS_PUBLIC_API(jsrefcount)
+JS_SuspendRequest(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth);
+
+#endif /* JS_THREADSAFE */
+
+extern JS_PUBLIC_API(void)
+JS_Lock(JSRuntime *rt);
+
+extern JS_PUBLIC_API(void)
+JS_Unlock(JSRuntime *rt);
+
+extern JS_PUBLIC_API(JSContext *)
+JS_NewContext(JSRuntime *rt, size_t stackChunkSize);
+
+extern JS_PUBLIC_API(void)
+JS_DestroyContext(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_DestroyContextNoGC(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_DestroyContextMaybeGC(JSContext *cx);
+
+extern JS_PUBLIC_API(void *)
+JS_GetContextPrivate(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_SetContextPrivate(JSContext *cx, void *data);
+
+extern JS_PUBLIC_API(JSRuntime *)
+JS_GetRuntime(JSContext *cx);
+
+extern JS_PUBLIC_API(JSContext *)
+JS_ContextIterator(JSRuntime *rt, JSContext **iterp);
+
+extern JS_PUBLIC_API(JSVersion)
+JS_GetVersion(JSContext *cx);
+
+extern JS_PUBLIC_API(JSVersion)
+JS_SetVersion(JSContext *cx, JSVersion version);
+
+extern JS_PUBLIC_API(const char *)
+JS_VersionToString(JSVersion version);
+
+extern JS_PUBLIC_API(JSVersion)
+JS_StringToVersion(const char *string);
+
+/*
+ * JS options are orthogonal to version, and may be freely composed with one
+ * another as well as with version.
+ *
+ * JSOPTION_VAROBJFIX is recommended -- see the comments associated with the
+ * prototypes for JS_ExecuteScript, JS_EvaluateScript, etc.
+ */
+#define JSOPTION_STRICT JS_BIT(0) /* warn on dubious practice */
+#define JSOPTION_WERROR JS_BIT(1) /* convert warning to error */
+#define JSOPTION_VAROBJFIX JS_BIT(2) /* make JS_EvaluateScript use
+ the last object on its 'obj'
+ param's scope chain as the
+ ECMA 'variables object' */
+#define JSOPTION_PRIVATE_IS_NSISUPPORTS \
+ JS_BIT(3) /* context private data points
+ to an nsISupports subclass */
+
+extern JS_PUBLIC_API(uint32)
+JS_GetOptions(JSContext *cx);
+
+extern JS_PUBLIC_API(uint32)
+JS_SetOptions(JSContext *cx, uint32 options);
+
+extern JS_PUBLIC_API(uint32)
+JS_ToggleOptions(JSContext *cx, uint32 options);
+
+extern JS_PUBLIC_API(const char *)
+JS_GetImplementationVersion(void);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetGlobalObject(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_SetGlobalObject(JSContext *cx, JSObject *obj);
+
+/*
+ * Initialize standard JS class constructors, prototypes, and any top-level
+ * functions and constants associated with the standard classes (e.g. isNaN
+ * for Number).
+ *
+ * NB: This sets cx's global object to obj if it was null.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_InitStandardClasses(JSContext *cx, JSObject *obj);
+
+/*
+ * Resolve id, which must contain either a string or an int, to a standard
+ * class name in obj if possible, defining the class's constructor and/or
+ * prototype and storing true in *resolved. If id does not name a standard
+ * class or a top-level property induced by initializing a standard class,
+ * store false in *resolved and just return true. Return false on error,
+ * as usual for JSBool result-typed API entry points.
+ *
+ * This API can be called directly from a global object class's resolve op,
+ * to define standard classes lazily. The class's enumerate op should call
+ * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in
+ * loops any classes not yet resolved lazily.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
+ JSBool *resolved);
+
+extern JS_PUBLIC_API(JSBool)
+JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetScopeChain(JSContext *cx);
+
+extern JS_PUBLIC_API(void *)
+JS_malloc(JSContext *cx, size_t nbytes);
+
+extern JS_PUBLIC_API(void *)
+JS_realloc(JSContext *cx, void *p, size_t nbytes);
+
+extern JS_PUBLIC_API(void)
+JS_free(JSContext *cx, void *p);
+
+extern JS_PUBLIC_API(char *)
+JS_strdup(JSContext *cx, const char *s);
+
+extern JS_PUBLIC_API(jsdouble *)
+JS_NewDouble(JSContext *cx, jsdouble d);
+
+extern JS_PUBLIC_API(JSBool)
+JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval);
+
+/*
+ * A JS GC root is a pointer to a JSObject *, JSString *, or jsdouble * that
+ * itself points into the GC heap (more recently, we support this extension:
+ * a root may be a pointer to a jsval v for which JSVAL_IS_GCTHING(v) is true).
+ *
+ * Therefore, you never pass JSObject *obj to JS_AddRoot(cx, obj). You always
+ * call JS_AddRoot(cx, &obj), passing obj by reference. And later, before obj
+ * or the structure it is embedded within goes out of scope or is freed, you
+ * must call JS_RemoveRoot(cx, &obj).
+ *
+ * Also, use JS_AddNamedRoot(cx, &structPtr->memberObj, "structPtr->memberObj")
+ * in preference to JS_AddRoot(cx, &structPtr->memberObj), in order to identify
+ * roots by their source callsites. This way, you can find the callsite while
+ * debugging if you should fail to do JS_RemoveRoot(cx, &structPtr->memberObj)
+ * before freeing structPtr's memory.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_AddRoot(JSContext *cx, void *rp);
+
+#ifdef NAME_ALL_GC_ROOTS
+#define JS_DEFINE_TO_TOKEN(def) #def
+#define JS_DEFINE_TO_STRING(def) JS_DEFINE_TO_TOKEN(def)
+#define JS_AddRoot(cx,rp) JS_AddNamedRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+#endif
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddNamedRoot(JSContext *cx, void *rp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveRoot(JSContext *cx, void *rp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveRootRT(JSRuntime *rt, void *rp);
+
+/*
+ * The last GC thing of each type (object, string, double, external string
+ * types) created on a given context is kept alive until another thing of the
+ * same type is created, using a newborn root in the context. These newborn
+ * roots help native code protect newly-created GC-things from GC invocations
+ * activated before those things can be rooted using local or global roots.
+ *
+ * However, the newborn roots can also entrain great gobs of garbage, so the
+ * JS_GC entry point clears them for the context on which GC is being forced.
+ * Embeddings may need to do likewise for all contexts.
+ *
+ * XXXbe See bug 40757 (http://bugzilla.mozilla.org/show_bug.cgi?id=40757),
+ * which proposes switching (with an #ifdef, alas, if we want to maintain API
+ * compatibility) to a JNI-like extensible local root frame stack model.
+ */
+extern JS_PUBLIC_API(void)
+JS_ClearNewbornRoots(JSContext *cx);
+
+#ifdef DEBUG
+extern JS_PUBLIC_API(void)
+JS_DumpNamedRoots(JSRuntime *rt,
+ void (*dump)(const char *name, void *rp, void *data),
+ void *data);
+#endif
+
+/*
+ * Call JS_MapGCRoots to map the GC's roots table using map(rp, name, data).
+ * The root is pointed at by rp; if the root is unnamed, name is null; data is
+ * supplied from the third parameter to JS_MapGCRoots.
+ *
+ * The map function should return JS_MAP_GCROOT_REMOVE to cause the currently
+ * enumerated root to be removed. To stop enumeration, set JS_MAP_GCROOT_STOP
+ * in the return value. To keep on mapping, return JS_MAP_GCROOT_NEXT. These
+ * constants are flags; you can OR them together.
+ *
+ * This function acquires and releases rt's GC lock around the mapping of the
+ * roots table, so the map function should run to completion in as few cycles
+ * as possible. Of course, map cannot call JS_GC, JS_MaybeGC, JS_BeginRequest,
+ * or any JS API entry point that acquires locks, without double-tripping or
+ * deadlocking on the GC lock.
+ *
+ * JS_MapGCRoots returns the count of roots that were successfully mapped.
+ */
+#define JS_MAP_GCROOT_NEXT 0 /* continue mapping entries */
+#define JS_MAP_GCROOT_STOP 1 /* stop mapping entries */
+#define JS_MAP_GCROOT_REMOVE 2 /* remove and free the current entry */
+
+typedef intN
+(* JS_DLL_CALLBACK JSGCRootMapFun)(void *rp, const char *name, void *data);
+
+extern JS_PUBLIC_API(uint32)
+JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data);
+
+extern JS_PUBLIC_API(JSBool)
+JS_LockGCThing(JSContext *cx, void *thing);
+
+extern JS_PUBLIC_API(JSBool)
+JS_LockGCThingRT(JSRuntime *rt, void *thing);
+
+extern JS_PUBLIC_API(JSBool)
+JS_UnlockGCThing(JSContext *cx, void *thing);
+
+extern JS_PUBLIC_API(JSBool)
+JS_UnlockGCThingRT(JSRuntime *rt, void *thing);
+
+/*
+ * For implementors of JSObjectOps.mark, to mark a GC-thing reachable via a
+ * property or other strong ref identified for debugging purposes by name.
+ * The name argument's storage needs to live only as long as the call to
+ * this routine.
+ *
+ * The final arg is used by GC_MARK_DEBUG code to build a ref path through
+ * the GC's live thing graph. Implementors of JSObjectOps.mark should pass
+ * its final arg through to this function when marking all GC-things that are
+ * directly reachable from the object being marked.
+ *
+ * See the JSMarkOp typedef in jspubtd.h, and the JSObjectOps struct below.
+ */
+extern JS_PUBLIC_API(void)
+JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg);
+
+extern JS_PUBLIC_API(void)
+JS_GC(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_MaybeGC(JSContext *cx);
+
+extern JS_PUBLIC_API(JSGCCallback)
+JS_SetGCCallback(JSContext *cx, JSGCCallback cb);
+
+extern JS_PUBLIC_API(JSGCCallback)
+JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb);
+
+extern JS_PUBLIC_API(JSBool)
+JS_IsAboutToBeFinalized(JSContext *cx, void *thing);
+
+/*
+ * Add an external string finalizer, one created by JS_NewExternalString (see
+ * below) using a type-code returned from this function, and that understands
+ * how to free or release the memory pointed at by JS_GetStringChars(str).
+ *
+ * Return a nonnegative type index if there is room for finalizer in the
+ * global GC finalizers table, else return -1. If the engine is compiled
+ * JS_THREADSAFE and used in a multi-threaded environment, this function must
+ * be invoked on the primordial thread only, at startup -- or else the entire
+ * program must single-thread itself while loading a module that calls this
+ * function.
+ */
+extern JS_PUBLIC_API(intN)
+JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer);
+
+/*
+ * Remove finalizer from the global GC finalizers table, returning its type
+ * code if found, -1 if not found.
+ *
+ * As with JS_AddExternalStringFinalizer, there is a threading restriction
+ * if you compile the engine JS_THREADSAFE: this function may be called for a
+ * given finalizer pointer on only one thread; different threads may call to
+ * remove distinct finalizers safely.
+ *
+ * You must ensure that all strings with finalizer's type have been collected
+ * before calling this function. Otherwise, string data will be leaked by the
+ * GC, for want of a finalizer to call.
+ */
+extern JS_PUBLIC_API(intN)
+JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer);
+
+/*
+ * Create a new JSString whose chars member refers to external memory, i.e.,
+ * memory requiring special, type-specific finalization. The type code must
+ * be a nonnegative return value from JS_AddExternalStringFinalizer.
+ */
+extern JS_PUBLIC_API(JSString *)
+JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type);
+
+/*
+ * Returns the external-string finalizer index for this string, or -1 if it is
+ * an "internal" (native to JS engine) string.
+ */
+extern JS_PUBLIC_API(intN)
+JS_GetExternalStringGCType(JSRuntime *rt, JSString *str);
+
+/*
+ * Sets maximum (if stack grows upward) or minimum (downward) legal stack byte
+ * address in limitAddr for the thread or process stack used by cx. To disable
+ * stack size checking, pass 0 for limitAddr.
+ */
+extern JS_PUBLIC_API(void)
+JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr);
+
+/************************************************************************/
+
+/*
+ * Classes, objects, and properties.
+ */
+
+/* For detailed comments on the function pointer types, see jspubtd.h. */
+struct JSClass {
+ const char *name;
+ uint32 flags;
+
+ /* Mandatory non-null function pointer members. */
+ JSPropertyOp addProperty;
+ JSPropertyOp delProperty;
+ JSPropertyOp getProperty;
+ JSPropertyOp setProperty;
+ JSEnumerateOp enumerate;
+ JSResolveOp resolve;
+ JSConvertOp convert;
+ JSFinalizeOp finalize;
+
+ /* Optionally non-null members start here. */
+ JSGetObjectOps getObjectOps;
+ JSCheckAccessOp checkAccess;
+ JSNative call;
+ JSNative construct;
+ JSXDRObjectOp xdrObject;
+ JSHasInstanceOp hasInstance;
+ JSMarkOp mark;
+ jsword spare;
+};
+
+#define JSCLASS_HAS_PRIVATE (1<<0) /* objects have private slot */
+#define JSCLASS_NEW_ENUMERATE (1<<1) /* has JSNewEnumerateOp hook */
+#define JSCLASS_NEW_RESOLVE (1<<2) /* has JSNewResolveOp hook */
+#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) /* private is (nsISupports *) */
+#define JSCLASS_SHARE_ALL_PROPERTIES (1<<4) /* all properties are SHARED */
+#define JSCLASS_NEW_RESOLVE_GETS_START (1<<5) /* JSNewResolveOp gets starting
+ object in prototype chain
+ passed in via *objp in/out
+ parameter */
+
+/*
+ * To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
+ * JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
+ * n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1.
+ */
+#define JSCLASS_RESERVED_SLOTS_SHIFT 8 /* room for 8 flags below */
+#define JSCLASS_RESERVED_SLOTS_WIDTH 8 /* and 16 above this field */
+#define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH)
+#define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \
+ << JSCLASS_RESERVED_SLOTS_SHIFT)
+#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \
+ >> JSCLASS_RESERVED_SLOTS_SHIFT) \
+ & JSCLASS_RESERVED_SLOTS_MASK)
+
+/* Initializer for unused members of statically initialized JSClass structs. */
+#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0
+
+/* For detailed comments on these function pointer types, see jspubtd.h. */
+struct JSObjectOps {
+ /* Mandatory non-null function pointer members. */
+ JSNewObjectMapOp newObjectMap;
+ JSObjectMapOp destroyObjectMap;
+ JSLookupPropOp lookupProperty;
+ JSDefinePropOp defineProperty;
+ JSPropertyIdOp getProperty;
+ JSPropertyIdOp setProperty;
+ JSAttributesOp getAttributes;
+ JSAttributesOp setAttributes;
+ JSPropertyIdOp deleteProperty;
+ JSConvertOp defaultValue;
+ JSNewEnumerateOp enumerate;
+ JSCheckAccessIdOp checkAccess;
+
+ /* Optionally non-null members start here. */
+ JSObjectOp thisObject;
+ JSPropertyRefOp dropProperty;
+ JSNative call;
+ JSNative construct;
+ JSXDRObjectOp xdrObject;
+ JSHasInstanceOp hasInstance;
+ JSSetObjectSlotOp setProto;
+ JSSetObjectSlotOp setParent;
+ JSMarkOp mark;
+ JSFinalizeOp clear;
+ JSGetRequiredSlotOp getRequiredSlot;
+ JSSetRequiredSlotOp setRequiredSlot;
+};
+
+/*
+ * Classes that expose JSObjectOps via a non-null getObjectOps class hook may
+ * derive a property structure from this struct, return a pointer to it from
+ * lookupProperty and defineProperty, and use the pointer to avoid rehashing
+ * in getAttributes and setAttributes.
+ *
+ * The jsid type contains either an int jsval (see JSVAL_IS_INT above), or an
+ * internal pointer that is opaque to users of this API, but which users may
+ * convert from and to a jsval using JS_ValueToId and JS_IdToValue.
+ */
+struct JSProperty {
+ jsid id;
+};
+
+struct JSIdArray {
+ jsint length;
+ jsid vector[1]; /* actually, length jsid words */
+};
+
+extern JS_PUBLIC_API(void)
+JS_DestroyIdArray(JSContext *cx, JSIdArray *ida);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ValueToId(JSContext *cx, jsval v, jsid *idp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_IdToValue(JSContext *cx, jsid id, jsval *vp);
+
+#define JSRESOLVE_QUALIFIED 0x01 /* resolve a qualified property id */
+#define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */
+
+extern JS_PUBLIC_API(JSBool)
+JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_EnumerateStub(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
+
+extern JS_PUBLIC_API(void)
+JS_FinalizeStub(JSContext *cx, JSObject *obj);
+
+struct JSConstDoubleSpec {
+ jsdouble dval;
+ const char *name;
+ uint8 flags;
+ uint8 spare[3];
+};
+
+/*
+ * To define an array element rather than a named property member, cast the
+ * element's index to (const char *) and initialize name with it, and set the
+ * JSPROP_INDEX bit in flags.
+ */
+struct JSPropertySpec {
+ const char *name;
+ int8 tinyid;
+ uint8 flags;
+ JSPropertyOp getter;
+ JSPropertyOp setter;
+};
+
+struct JSFunctionSpec {
+ const char *name;
+ JSNative call;
+ uint8 nargs;
+ uint8 flags;
+ uint16 extra; /* number of arg slots for local GC roots */
+};
+
+extern JS_PUBLIC_API(JSObject *)
+JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
+ JSClass *clasp, JSNative constructor, uintN nargs,
+ JSPropertySpec *ps, JSFunctionSpec *fs,
+ JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
+
+#ifdef JS_THREADSAFE
+extern JS_PUBLIC_API(JSClass *)
+JS_GetClass(JSContext *cx, JSObject *obj);
+
+#define JS_GET_CLASS(cx,obj) JS_GetClass(cx, obj)
+#else
+extern JS_PUBLIC_API(JSClass *)
+JS_GetClass(JSObject *obj);
+
+#define JS_GET_CLASS(cx,obj) JS_GetClass(obj)
+#endif
+
+extern JS_PUBLIC_API(JSBool)
+JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv);
+
+extern JS_PUBLIC_API(void *)
+JS_GetPrivate(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetPrivate(JSContext *cx, JSObject *obj, void *data);
+
+extern JS_PUBLIC_API(void *)
+JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
+ jsval *argv);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetPrototype(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetParent(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetConstructor(JSContext *cx, JSObject *proto);
+
+/*
+ * Get a unique identifier for obj, good for the lifetime of obj (even if it
+ * is moved by a copying GC). Return false on failure (likely out of memory),
+ * and true with *idp containing the unique id on success.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent, uintN argc, jsval *argv);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
+ JSObject *proto, uintN attrs);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs);
+
+/*
+ * Determine the attributes (JSPROP_* flags) of a property on a given object.
+ *
+ * If the object does not have a property by that name, *foundp will be
+ * JS_FALSE and the value of *attrsp is undefined.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+ uintN *attrsp, JSBool *foundp);
+
+/*
+ * Set the attributes of a property on a given object.
+ *
+ * If the object does not have a property by that name, *foundp will be
+ * JS_FALSE and nothing will be altered.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+ uintN attrs, JSBool *foundp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
+ int8 tinyid, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
+ const char *alias);
+
+extern JS_PUBLIC_API(JSBool)
+JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
+ jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefineUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs);
+
+/*
+ * Determine the attributes (JSPROP_* flags) of a property on a given object.
+ *
+ * If the object does not have a property by that name, *foundp will be
+ * JS_FALSE and the value of *attrsp is undefined.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ uintN *attrsp, JSBool *foundp);
+
+/*
+ * Set the attributes of a property on a given object.
+ *
+ * If the object does not have a property by that name, *foundp will be
+ * JS_FALSE and nothing will be altered.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ uintN attrs, JSBool *foundp);
+
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ int8 tinyid, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs);
+
+extern JS_PUBLIC_API(JSBool)
+JS_LookupUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *rval);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector);
+
+extern JS_PUBLIC_API(JSBool)
+JS_IsArrayObject(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length);
+
+extern JS_PUBLIC_API(JSBool)
+JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias);
+
+extern JS_PUBLIC_API(JSBool)
+JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval);
+
+extern JS_PUBLIC_API(void)
+JS_ClearScope(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSIdArray *)
+JS_Enumerate(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
+ jsval *vp, uintN *attrsp);
+
+extern JS_PUBLIC_API(JSCheckAccessOp)
+JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v);
+
+/************************************************************************/
+
+/*
+ * Security protocol.
+ */
+struct JSPrincipals {
+ char *codebase;
+ void * (* JS_DLL_CALLBACK getPrincipalArray)(JSContext *cx, JSPrincipals *);
+ JSBool (* JS_DLL_CALLBACK globalPrivilegesEnabled)(JSContext *cx, JSPrincipals *);
+
+ /* Don't call "destroy"; use reference counting macros below. */
+ jsrefcount refcount;
+ void (* JS_DLL_CALLBACK destroy)(JSContext *cx, struct JSPrincipals *);
+};
+
+#ifdef JS_THREADSAFE
+#define JSPRINCIPALS_HOLD(cx, principals) JS_HoldPrincipals(cx,principals)
+#define JSPRINCIPALS_DROP(cx, principals) JS_DropPrincipals(cx,principals)
+
+extern JS_PUBLIC_API(jsrefcount)
+JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals);
+
+extern JS_PUBLIC_API(jsrefcount)
+JS_DropPrincipals(JSContext *cx, JSPrincipals *principals);
+
+#else
+#define JSPRINCIPALS_HOLD(cx, principals) (++(principals)->refcount)
+#define JSPRINCIPALS_DROP(cx, principals) \
+ ((--(principals)->refcount == 0) \
+ ? ((*(principals)->destroy)((cx), (principals)), 0) \
+ : (principals)->refcount)
+#endif
+
+extern JS_PUBLIC_API(JSPrincipalsTranscoder)
+JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px);
+
+extern JS_PUBLIC_API(JSObjectPrincipalsFinder)
+JS_SetObjectPrincipalsFinder(JSContext *cx, JSObjectPrincipalsFinder fop);
+
+/************************************************************************/
+
+/*
+ * Functions and scripts.
+ */
+extern JS_PUBLIC_API(JSFunction *)
+JS_NewFunction(JSContext *cx, JSNative call, uintN nargs, uintN flags,
+ JSObject *parent, const char *name);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetFunctionObject(JSFunction *fun);
+
+/*
+ * Deprecated, useful only for diagnostics. Use JS_GetFunctionId instead for
+ * anonymous vs. "anonymous" disambiguation and Unicode fidelity.
+ */
+extern JS_PUBLIC_API(const char *)
+JS_GetFunctionName(JSFunction *fun);
+
+/*
+ * Return the function's identifier as a JSString, or null if fun is unnamed.
+ * The returned string lives as long as fun, so you don't need to root a saved
+ * reference to it if fun is well-connected or rooted, and provided you bound
+ * the use of the saved reference by fun's lifetime.
+ *
+ * Prefer JS_GetFunctionId over JS_GetFunctionName because it returns null for
+ * truly anonymous functions, and because it doesn't chop to ISO-Latin-1 chars
+ * from UTF-16-ish jschars.
+ */
+extern JS_PUBLIC_API(JSString *)
+JS_GetFunctionId(JSFunction *fun);
+
+/*
+ * Return JSFUN_* flags for fun.
+ */
+extern JS_PUBLIC_API(uintN)
+JS_GetFunctionFlags(JSFunction *fun);
+
+/*
+ * Infallible predicate to test whether obj is a function object (faster than
+ * comparing obj's class name to "Function", but equivalent unless someone has
+ * overwritten the "Function" identifier with a different constructor and then
+ * created instances using that constructor that might be passed in as obj).
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ObjectIsFunction(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
+ uintN nargs, uintN attrs);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
+
+/*
+ * Given a buffer, return JS_FALSE if the buffer might become a valid
+ * javascript statement with the addition of more lines. Otherwise return
+ * JS_TRUE. The intent is to support interactive compilation - accumulate
+ * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to
+ * the compiler.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
+ const char *bytes, size_t length);
+
+/*
+ * The JSScript objects returned by the following functions refer to string and
+ * other kinds of literals, including doubles and RegExp objects. These
+ * literals are vulnerable to garbage collection; to root script objects and
+ * prevent literals from being collected, create a rootable object using
+ * JS_NewScriptObject, and root the resulting object using JS_Add[Named]Root.
+ */
+extern JS_PUBLIC_API(JSScript *)
+JS_CompileScript(JSContext *cx, JSObject *obj,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_CompileUCScript(JSContext *cx, JSObject *obj,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
+ FILE *fh);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
+ const char *filename, FILE *fh,
+ JSPrincipals *principals);
+
+/*
+ * NB: you must use JS_NewScriptObject and root a pointer to its return value
+ * in order to keep a JSScript and its atoms safe from garbage collection after
+ * creating the script via JS_Compile* and before a JS_ExecuteScript* call.
+ * E.g., and without error checks:
+ *
+ * JSScript *script = JS_CompileFile(cx, global, filename);
+ * JSObject *scrobj = JS_NewScriptObject(cx, script);
+ * JS_AddNamedRoot(cx, &scrobj, "scrobj");
+ * do {
+ * jsval result;
+ * JS_ExecuteScript(cx, global, script, &result);
+ * JS_GC();
+ * } while (!JSVAL_IS_BOOLEAN(result) || JSVAL_TO_BOOLEAN(result));
+ * JS_RemoveRoot(cx, &scrobj);
+ */
+extern JS_PUBLIC_API(JSObject *)
+JS_NewScriptObject(JSContext *cx, JSScript *script);
+
+/*
+ * Infallible getter for a script's object. If JS_NewScriptObject has not been
+ * called on script yet, the return value will be null.
+ */
+extern JS_PUBLIC_API(JSObject *)
+JS_GetScriptObject(JSScript *script);
+
+extern JS_PUBLIC_API(void)
+JS_DestroyScript(JSContext *cx, JSScript *script);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
+ uintN nargs, const char **argnames,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals, const char *name,
+ uintN nargs, const char **argnames,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
+ uintN nargs, const char **argnames,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals, const char *name,
+ uintN nargs, const char **argnames,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno);
+
+extern JS_PUBLIC_API(JSString *)
+JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
+ uintN indent);
+
+/*
+ * API extension: OR this into indent to avoid pretty-printing the decompiled
+ * source resulting from JS_DecompileFunction{,Body}.
+ */
+#define JS_DONT_PRETTY_PRINT ((uintN)0x8000)
+
+extern JS_PUBLIC_API(JSString *)
+JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent);
+
+extern JS_PUBLIC_API(JSString *)
+JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent);
+
+/*
+ * NB: JS_ExecuteScript, JS_ExecuteScriptPart, and the JS_Evaluate*Script*
+ * quadruplets all use the obj parameter as the initial scope chain header,
+ * the 'this' keyword value, and the variables object (ECMA parlance for where
+ * 'var' and 'function' bind names) of the execution context for script.
+ *
+ * Using obj as the variables object is problematic if obj's parent (which is
+ * the scope chain link; see JS_SetParent and JS_NewObject) is not null: in
+ * this case, variables created by 'var x = 0', e.g., go in obj, but variables
+ * created by assignment to an unbound id, 'x = 0', go in the last object on
+ * the scope chain linked by parent.
+ *
+ * ECMA calls that last scoping object the "global object", but note that many
+ * embeddings have several such objects. ECMA requires that "global code" be
+ * executed with the variables object equal to this global object. But these
+ * JS API entry points provide freedom to execute code against a "sub-global",
+ * i.e., a parented or scoped object, in which case the variables object will
+ * differ from the last object on the scope chain, resulting in confusing and
+ * non-ECMA explicit vs. implicit variable creation.
+ *
+ * Caveat embedders: unless you already depend on this buggy variables object
+ * binding behavior, you should call JS_SetOptions(cx, JSOPTION_VAROBJFIX) or
+ * JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_VAROBJFIX) -- the latter if
+ * someone may have set other options on cx already -- for each context in the
+ * application, if you pass parented objects as the obj parameter, or may ever
+ * pass such objects in the future.
+ *
+ * Why a runtime option? The alternative is to add six or so new API entry
+ * points with signatures matching the following six, and that doesn't seem
+ * worth the code bloat cost. Such new entry points would probably have less
+ * obvious names, too, so would not tend to be used. The JS_SetOption call,
+ * OTOH, can be more easily hacked into existing code that does not depend on
+ * the bug; such code can continue to use the familiar JS_EvaluateScript,
+ * etc., entry points.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval);
+
+/*
+ * Execute either the function-defining prolog of a script, or the script's
+ * main body, but not both.
+ */
+typedef enum JSExecPart { JSEXEC_PROLOG, JSEXEC_MAIN } JSExecPart;
+
+extern JS_PUBLIC_API(JSBool)
+JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
+ JSExecPart part, jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_EvaluateScript(JSContext *cx, JSObject *obj,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
+ const jschar *chars, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const jschar *chars, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
+ jsval *argv, jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
+ jsval *argv, jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
+ jsval *argv, jsval *rval);
+
+extern JS_PUBLIC_API(JSBranchCallback)
+JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb);
+
+extern JS_PUBLIC_API(JSBool)
+JS_IsRunning(JSContext *cx);
+
+extern JS_PUBLIC_API(JSBool)
+JS_IsConstructing(JSContext *cx);
+
+/*
+ * Returns true if a script is executing and its current bytecode is a set
+ * (assignment) operation, even if there are native (no script) stack frames
+ * between the script and the caller to JS_IsAssigning.
+ */
+extern JS_FRIEND_API(JSBool)
+JS_IsAssigning(JSContext *cx);
+
+/*
+ * Set the second return value, which should be a string or int jsval that
+ * identifies a property in the returned object, to form an ECMA reference
+ * type value (obj, id). Only native methods can return reference types,
+ * and if the returned value is used on the left-hand side of an assignment
+ * op, the identified property will be set. If the return value is in an
+ * r-value, the interpreter just gets obj[id]'s value.
+ */
+extern JS_PUBLIC_API(void)
+JS_SetCallReturnValue2(JSContext *cx, jsval v);
+
+/************************************************************************/
+
+/*
+ * Strings.
+ *
+ * NB: JS_NewString takes ownership of bytes on success, avoiding a copy; but
+ * on error (signified by null return), it leaves bytes owned by the caller.
+ * So the caller must free bytes in the error case, if it has no use for them.
+ * In contrast, all the JS_New*StringCopy* functions do not take ownership of
+ * the character memory passed to them -- they copy it.
+ */
+extern JS_PUBLIC_API(JSString *)
+JS_NewString(JSContext *cx, char *bytes, size_t length);
+
+extern JS_PUBLIC_API(JSString *)
+JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
+
+extern JS_PUBLIC_API(JSString *)
+JS_NewStringCopyZ(JSContext *cx, const char *s);
+
+extern JS_PUBLIC_API(JSString *)
+JS_InternString(JSContext *cx, const char *s);
+
+extern JS_PUBLIC_API(JSString *)
+JS_NewUCString(JSContext *cx, jschar *chars, size_t length);
+
+extern JS_PUBLIC_API(JSString *)
+JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n);
+
+extern JS_PUBLIC_API(JSString *)
+JS_NewUCStringCopyZ(JSContext *cx, const jschar *s);
+
+extern JS_PUBLIC_API(JSString *)
+JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
+
+extern JS_PUBLIC_API(JSString *)
+JS_InternUCString(JSContext *cx, const jschar *s);
+
+extern JS_PUBLIC_API(char *)
+JS_GetStringBytes(JSString *str);
+
+extern JS_PUBLIC_API(jschar *)
+JS_GetStringChars(JSString *str);
+
+extern JS_PUBLIC_API(size_t)
+JS_GetStringLength(JSString *str);
+
+extern JS_PUBLIC_API(intN)
+JS_CompareStrings(JSString *str1, JSString *str2);
+
+/*
+ * Mutable string support. A string's characters are never mutable in this JS
+ * implementation, but a growable string has a buffer that can be reallocated,
+ * and a dependent string is a substring of another (growable, dependent, or
+ * immutable) string. The direct data members of the (opaque to API clients)
+ * JSString struct may be changed in a single-threaded way for growable and
+ * dependent strings.
+ *
+ * Therefore mutable strings cannot be used by more than one thread at a time.
+ * You may call JS_MakeStringImmutable to convert the string from a mutable
+ * (growable or dependent) string to an immutable (and therefore thread-safe)
+ * string. The engine takes care of converting growable and dependent strings
+ * to immutable for you if you store strings in multi-threaded objects using
+ * JS_SetProperty or kindred API entry points.
+ *
+ * If you store a JSString pointer in a native data structure that is (safely)
+ * accessible to multiple threads, you must call JS_MakeStringImmutable before
+ * retiring the store.
+ */
+extern JS_PUBLIC_API(JSString *)
+JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length);
+
+/*
+ * Create a dependent string, i.e., a string that owns no character storage,
+ * but that refers to a slice of another string's chars. Dependent strings
+ * are mutable by definition, so the thread safety comments above apply.
+ */
+extern JS_PUBLIC_API(JSString *)
+JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
+ size_t length);
+
+/*
+ * Concatenate two strings, resulting in a new growable string. If you create
+ * the left string and pass it to JS_ConcatStrings on a single thread, try to
+ * use JS_NewGrowableString to create the left string -- doing so helps Concat
+ * avoid allocating a new buffer for the result and copying left's chars into
+ * the new buffer. See above for thread safety comments.
+ */
+extern JS_PUBLIC_API(JSString *)
+JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
+
+/*
+ * Convert a dependent string into an independent one. This function does not
+ * change the string's mutability, so the thread safety comments above apply.
+ */
+extern JS_PUBLIC_API(const jschar *)
+JS_UndependString(JSContext *cx, JSString *str);
+
+/*
+ * Convert a mutable string (either growable or dependent) into an immutable,
+ * thread-safe one.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_MakeStringImmutable(JSContext *cx, JSString *str);
+
+/************************************************************************/
+
+/*
+ * Locale specific string conversion callback.
+ */
+struct JSLocaleCallbacks {
+ JSLocaleToUpperCase localeToUpperCase;
+ JSLocaleToLowerCase localeToLowerCase;
+ JSLocaleCompare localeCompare;
+};
+
+/*
+ * Establish locale callbacks. The pointer must persist as long as the
+ * JSContext. Passing NULL restores the default behaviour.
+ */
+extern JS_PUBLIC_API(void)
+JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks);
+
+/*
+ * Return the address of the current locale callbacks struct, which may
+ * be NULL.
+ */
+extern JS_PUBLIC_API(JSLocaleCallbacks *)
+JS_GetLocaleCallbacks(JSContext *cx);
+
+/************************************************************************/
+
+/*
+ * Error reporting.
+ */
+
+/*
+ * Report an exception represented by the sprintf-like conversion of format
+ * and its arguments. This exception message string is passed to a pre-set
+ * JSErrorReporter function (set by JS_SetErrorReporter; see jspubtd.h for
+ * the JSErrorReporter typedef).
+ */
+extern JS_PUBLIC_API(void)
+JS_ReportError(JSContext *cx, const char *format, ...);
+
+/*
+ * Use an errorNumber to retrieve the format string, args are char *
+ */
+extern JS_PUBLIC_API(void)
+JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
+ void *userRef, const uintN errorNumber, ...);
+
+/*
+ * Use an errorNumber to retrieve the format string, args are jschar *
+ */
+extern JS_PUBLIC_API(void)
+JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
+ void *userRef, const uintN errorNumber, ...);
+
+/*
+ * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)).
+ * Return true if there was no error trying to issue the warning, and if the
+ * warning was not converted into an error due to the JSOPTION_WERROR option
+ * being set, false otherwise.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_ReportWarning(JSContext *cx, const char *format, ...);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
+ JSErrorCallback errorCallback, void *userRef,
+ const uintN errorNumber, ...);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
+ JSErrorCallback errorCallback, void *userRef,
+ const uintN errorNumber, ...);
+
+/*
+ * Complain when out of memory.
+ */
+extern JS_PUBLIC_API(void)
+JS_ReportOutOfMemory(JSContext *cx);
+
+struct JSErrorReport {
+ const char *filename; /* source file name, URL, etc., or null */
+ uintN lineno; /* source line number */
+ const char *linebuf; /* offending source line without final \n */
+ const char *tokenptr; /* pointer to error token in linebuf */
+ const jschar *uclinebuf; /* unicode (original) line buffer */
+ const jschar *uctokenptr; /* unicode (original) token pointer */
+ uintN flags; /* error/warning, etc. */
+ uintN errorNumber; /* the error number, e.g. see js.msg */
+ const jschar *ucmessage; /* the (default) error message */
+ const jschar **messageArgs; /* arguments for the error message */
+};
+
+/*
+ * JSErrorReport flag values. These may be freely composed.
+ */
+#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */
+#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */
+#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */
+#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */
+
+/*
+ * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception
+ * has been thrown for this runtime error, and the host should ignore it.
+ * Exception-aware hosts should also check for JS_IsExceptionPending if
+ * JS_ExecuteScript returns failure, and signal or propagate the exception, as
+ * appropriate.
+ */
+#define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0)
+#define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0)
+#define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0)
+
+extern JS_PUBLIC_API(JSErrorReporter)
+JS_SetErrorReporter(JSContext *cx, JSErrorReporter er);
+
+/************************************************************************/
+
+/*
+ * Regular Expressions.
+ */
+#define JSREG_FOLD 0x01 /* fold uppercase to lowercase */
+#define JSREG_GLOB 0x02 /* global exec, creates array of matches */
+#define JSREG_MULTILINE 0x04 /* treat ^ and $ as begin and end of line */
+
+extern JS_PUBLIC_API(JSObject *)
+JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags);
+
+extern JS_PUBLIC_API(void)
+JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline);
+
+extern JS_PUBLIC_API(void)
+JS_ClearRegExpStatics(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_ClearRegExpRoots(JSContext *cx);
+
+/* TODO: compile, exec, get/set other statics... */
+
+/************************************************************************/
+
+extern JS_PUBLIC_API(JSBool)
+JS_IsExceptionPending(JSContext *cx);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetPendingException(JSContext *cx, jsval *vp);
+
+extern JS_PUBLIC_API(void)
+JS_SetPendingException(JSContext *cx, jsval v);
+
+extern JS_PUBLIC_API(void)
+JS_ClearPendingException(JSContext *cx);
+
+/*
+ * Save the current exception state. This takes a snapshot of cx's current
+ * exception state without making any change to that state.
+ *
+ * The returned state pointer MUST be passed later to JS_RestoreExceptionState
+ * (to restore that saved state, overriding any more recent state) or else to
+ * JS_DropExceptionState (to free the state struct in case it is not correct
+ * or desirable to restore it). Both Restore and Drop free the state struct,
+ * so callers must stop using the pointer returned from Save after calling the
+ * Release or Drop API.
+ */
+extern JS_PUBLIC_API(JSExceptionState *)
+JS_SaveExceptionState(JSContext *cx);
+
+extern JS_PUBLIC_API(void)
+JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state);
+
+extern JS_PUBLIC_API(void)
+JS_DropExceptionState(JSContext *cx, JSExceptionState *state);
+
+/*
+ * If the given value is an exception object that originated from an error,
+ * the exception will contain an error report struct, and this API will return
+ * the address of that struct. Otherwise, it returns NULL. The lifetime of
+ * the error report struct that might be returned is the same as the lifetime
+ * of the exception object.
+ */
+extern JS_PUBLIC_API(JSErrorReport *)
+JS_ErrorFromException(JSContext *cx, jsval v);
+
+#ifdef JS_THREADSAFE
+
+/*
+ * Associate the current thread with the given context. This is done
+ * implicitly by JS_NewContext.
+ *
+ * Returns the old thread id for this context, which should be treated as
+ * an opaque value. This value is provided for comparison to 0, which
+ * indicates that ClearContextThread has been called on this context
+ * since the last SetContextThread, or non-0, which indicates the opposite.
+ */
+extern JS_PUBLIC_API(jsword)
+JS_GetContextThread(JSContext *cx);
+
+extern JS_PUBLIC_API(jsword)
+JS_SetContextThread(JSContext *cx);
+
+extern JS_PUBLIC_API(intN)
+JS_ClearContextThread(JSContext *cx);
+
+#endif /* JS_THREADSAFE */
+
+/************************************************************************/
+
+JS_END_EXTERN_C
+
+#endif /* jsapi_h___ */
diff --git a/src/dom/js/jsarena.c b/src/dom/js/jsarena.c
new file mode 100644
index 000000000..4cc2e7c53
--- /dev/null
+++ b/src/dom/js/jsarena.c
@@ -0,0 +1,565 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Lifetime-based fast allocation, inspired by much prior art, including
+ * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
+ * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsbit.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jslock.h"
+
+static JSArena *arena_freelist;
+
+#ifdef JS_THREADSAFE
+static JSLock *arena_freelist_lock;
+#endif
+
+#ifdef JS_ARENAMETER
+static JSArenaStats *arena_stats_list;
+
+#define COUNT(pool,what) (pool)->stats.what++
+#else
+#define COUNT(pool,what) /* nothing */
+#endif
+
+#define JS_ARENA_DEFAULT_ALIGN sizeof(double)
+
+JS_PUBLIC_API(void)
+JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, size_t align)
+{
+#ifdef JS_THREADSAFE
+ /* Must come through here once in primordial thread to init safely! */
+ if (!arena_freelist_lock) {
+ arena_freelist_lock = JS_NEW_LOCK();
+ JS_ASSERT(arena_freelist_lock);
+ }
+#endif
+ if (align == 0)
+ align = JS_ARENA_DEFAULT_ALIGN;
+ pool->mask = JS_BITMASK(JS_CeilingLog2(align));
+ pool->first.next = NULL;
+ pool->first.base = pool->first.avail = pool->first.limit =
+ JS_ARENA_ALIGN(pool, &pool->first + 1);
+ pool->current = &pool->first;
+ pool->arenasize = size;
+#ifdef JS_ARENAMETER
+ memset(&pool->stats, 0, sizeof pool->stats);
+ pool->stats.name = strdup(name);
+ pool->stats.next = arena_stats_list;
+ arena_stats_list = &pool->stats;
+#endif
+}
+
+/*
+ * An allocation that consumes more than pool->arenasize also has a header
+ * pointing back to its previous arena's next member. This header is not
+ * included in [a->base, a->limit), so its space can't be wrongly claimed.
+ *
+ * As the header is a pointer, it must be well-aligned. If pool->mask is
+ * greater than or equal to POINTER_MASK, the header just preceding a->base
+ * for an oversized arena a is well-aligned, because a->base is well-aligned.
+ * However, we may need to add more space to pad the JSArena ** back-pointer
+ * so that it lies just behind a->base, because a might not be aligned such
+ * that (jsuword)(a + 1) is on a pointer boundary.
+ *
+ * By how much must we pad? Let M be the alignment modulus for pool and P
+ * the modulus for a pointer. Given M >= P, the greatest distance between a
+ * pointer aligned on an M boundary and one aligned on a P boundary is M-P.
+ * If M and P are powers of two, then M-P = (pool->mask - POINTER_MASK).
+ *
+ * How much extra padding might spill over unused into the remainder of the
+ * allocation, in the worst case (where M > P)?
+ *
+ * If we add M-P to the nominal back-pointer address and then round down to
+ * align on a P boundary, we will use at most M-P bytes of padding, and at
+ * least P (M > P => M >= 2P; M == 2P gives the least padding, P). So if we
+ * use P bytes of padding, then we will overallocate a by P+M-1 bytes, as we
+ * also add M-1 to the estimated size in case malloc returns an odd pointer.
+ * a->limit must include this overestimation to satisfy a->avail in [a->base,
+ * a->limit].
+ *
+ * Similarly, if pool->mask is less than POINTER_MASK, we must include enough
+ * space in the header size to align the back-pointer on a P boundary so that
+ * it can be found by subtracting P from a->base. This means a->base must be
+ * on a P boundary, even though subsequent allocations from a may be aligned
+ * on a lesser (M) boundary. Given powers of two M and P as above, the extra
+ * space needed when P > M is P-M or POINTER_MASK - pool->mask.
+ *
+ * The size of a header including padding is given by the HEADER_SIZE macro,
+ * below, for any pool (for any value of M).
+ *
+ * The mask to align a->base for any pool is (pool->mask | POINTER_MASK), or
+ * HEADER_BASE_MASK(pool).
+ *
+ * PTR_TO_HEADER computes the address of the back-pointer, given an oversized
+ * allocation at p. By definition, p must be a->base for the arena a that
+ * contains p. GET_HEADER and SET_HEADER operate on an oversized arena a, in
+ * the case of SET_HEADER with back-pointer ap.
+ */
+#define POINTER_MASK ((jsuword)(JS_ALIGN_OF_POINTER - 1))
+#define HEADER_SIZE(pool) (sizeof(JSArena **) \
+ + (((pool)->mask < POINTER_MASK) \
+ ? POINTER_MASK - (pool)->mask \
+ : (pool)->mask - POINTER_MASK))
+#define HEADER_BASE_MASK(pool) ((pool)->mask | POINTER_MASK)
+#define PTR_TO_HEADER(pool,p) (JS_ASSERT(((jsuword)(p) \
+ & HEADER_BASE_MASK(pool)) \
+ == 0), \
+ (JSArena ***)(p) - 1)
+#define GET_HEADER(pool,a) (*PTR_TO_HEADER(pool, (a)->base))
+#define SET_HEADER(pool,a,ap) (*PTR_TO_HEADER(pool, (a)->base) = (ap))
+
+JS_PUBLIC_API(void *)
+JS_ArenaAllocate(JSArenaPool *pool, size_t nb)
+{
+ JSArena **ap, **bp, *a, *b;
+ jsuword extra, hdrsz, gross, sz;
+ void *p;
+
+ /* Search pool from current forward till we find or make enough space. */
+ JS_ASSERT((nb & pool->mask) == 0);
+ for (a = pool->current; a->avail + nb > a->limit; pool->current = a) {
+ ap = &a->next;
+ if (!*ap) {
+ /* Not enough space in pool -- try to reclaim a free arena. */
+ extra = (nb > pool->arenasize) ? HEADER_SIZE(pool) : 0;
+ hdrsz = sizeof *a + extra + pool->mask;
+ gross = hdrsz + JS_MAX(nb, pool->arenasize);
+ bp = &arena_freelist;
+ JS_ACQUIRE_LOCK(arena_freelist_lock);
+ while ((b = *bp) != NULL) {
+ /*
+ * Insist on exact arenasize match if nb is not greater than
+ * arenasize. Otherwise take any arena big enough, but not by
+ * more than gross + arenasize.
+ */
+ sz = JS_UPTRDIFF(b->limit, b);
+ if (extra
+ ? sz >= gross && sz <= gross + pool->arenasize
+ : sz == gross) {
+ *bp = b->next;
+ JS_RELEASE_LOCK(arena_freelist_lock);
+ b->next = NULL;
+ COUNT(pool, nreclaims);
+ goto claim;
+ }
+ bp = &b->next;
+ }
+
+ /* Nothing big enough on the freelist, so we must malloc. */
+ JS_RELEASE_LOCK(arena_freelist_lock);
+ b = (JSArena *) malloc(gross);
+ if (!b)
+ return 0;
+ b->next = NULL;
+ b->limit = (jsuword)b + gross;
+ JS_COUNT_ARENA(pool,++);
+ COUNT(pool, nmallocs);
+
+ claim:
+ /* If oversized, store ap in the header, just before a->base. */
+ *ap = a = b;
+ JS_ASSERT(gross <= JS_UPTRDIFF(a->limit, a));
+ if (extra) {
+ a->base = a->avail =
+ ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool);
+ SET_HEADER(pool, a, ap);
+ } else {
+ a->base = a->avail = JS_ARENA_ALIGN(pool, a + 1);
+ }
+ continue;
+ }
+ a = *ap; /* move to next arena */
+ }
+
+ p = (void *)a->avail;
+ a->avail += nb;
+ JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ return p;
+}
+
+JS_PUBLIC_API(void *)
+JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr)
+{
+ JSArena **ap, *a, *b;
+ jsuword boff, aoff, extra, hdrsz, gross;
+
+ /*
+ * Use the oversized-single-allocation header to avoid searching for ap.
+ * See JS_ArenaAllocate, the SET_HEADER call.
+ */
+ if (size > pool->arenasize) {
+ ap = *PTR_TO_HEADER(pool, p);
+ a = *ap;
+ } else {
+ ap = &pool->first.next;
+ while ((a = *ap) != pool->current)
+ ap = &a->next;
+ }
+
+ JS_ASSERT(a->base == (jsuword)p);
+ boff = JS_UPTRDIFF(a->base, a);
+ aoff = size + incr;
+ JS_ASSERT(aoff > pool->arenasize);
+ extra = HEADER_SIZE(pool); /* oversized header holds ap */
+ hdrsz = sizeof *a + extra + pool->mask; /* header and alignment slop */
+ gross = hdrsz + aoff;
+ a = (JSArena *) realloc(a, gross);
+ if (!a)
+ return NULL;
+#ifdef JS_ARENAMETER
+ pool->stats.nreallocs++;
+#endif
+
+ if (a != *ap) {
+ /* Oops, realloc moved the allocation: update other pointers to a. */
+ if (pool->current == *ap)
+ pool->current = a;
+ b = a->next;
+ if (b && b->avail - b->base > pool->arenasize) {
+ JS_ASSERT(GET_HEADER(pool, b) == &(*ap)->next);
+ SET_HEADER(pool, b, &a->next);
+ }
+
+ /* Now update *ap, the next link of the arena before a. */
+ *ap = a;
+ }
+
+ a->base = ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool);
+ a->limit = (jsuword)a + gross;
+ a->avail = JS_ARENA_ALIGN(pool, a->base + aoff);
+ JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+
+ /* Check whether realloc aligned differently, and copy if necessary. */
+ if (boff != JS_UPTRDIFF(a->base, a))
+ memmove((void *)a->base, (char *)a + boff, size);
+
+ /* Store ap in the oversized-load arena header. */
+ SET_HEADER(pool, a, ap);
+ return (void *)a->base;
+}
+
+JS_PUBLIC_API(void *)
+JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr)
+{
+ void *newp;
+
+ /*
+ * If p points to an oversized allocation, it owns an entire arena, so we
+ * can simply realloc the arena.
+ */
+ if (size > pool->arenasize)
+ return JS_ArenaRealloc(pool, p, size, incr);
+
+ JS_ARENA_ALLOCATE(newp, pool, size + incr);
+ if (newp)
+ memcpy(newp, p, size);
+ return newp;
+}
+
+/*
+ * Free tail arenas linked after head, which may not be the true list head.
+ * Reset pool->current to point to head in case it pointed at a tail arena.
+ */
+static void
+FreeArenaList(JSArenaPool *pool, JSArena *head, JSBool reallyFree)
+{
+ JSArena **ap, *a;
+
+ ap = &head->next;
+ a = *ap;
+ if (!a)
+ return;
+
+#ifdef DEBUG
+ do {
+ JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ a->avail = a->base;
+ JS_CLEAR_UNUSED(a);
+ } while ((a = a->next) != NULL);
+ a = *ap;
+#endif
+
+ if (reallyFree) {
+ do {
+ *ap = a->next;
+ JS_CLEAR_ARENA(a);
+ JS_COUNT_ARENA(pool,--);
+ free(a);
+ } while ((a = *ap) != NULL);
+ } else {
+ /* Insert the whole arena chain at the front of the freelist. */
+ do {
+ ap = &(*ap)->next;
+ } while (*ap);
+ JS_ACQUIRE_LOCK(arena_freelist_lock);
+ *ap = arena_freelist;
+ arena_freelist = a;
+ JS_RELEASE_LOCK(arena_freelist_lock);
+ head->next = NULL;
+ }
+
+ pool->current = head;
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaRelease(JSArenaPool *pool, char *mark)
+{
+ JSArena *a;
+
+ for (a = &pool->first; a; a = a->next) {
+ JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+
+ if (JS_UPTRDIFF(mark, a->base) <= JS_UPTRDIFF(a->avail, a->base)) {
+ a->avail = JS_ARENA_ALIGN(pool, mark);
+ JS_ASSERT(a->avail <= a->limit);
+ FreeArenaList(pool, a, JS_TRUE);
+ return;
+ }
+ }
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaFreeAllocation(JSArenaPool *pool, void *p, size_t size)
+{
+ JSArena **ap, *a, *b;
+ jsuword q;
+
+ /*
+ * If the allocation is oversized, it consumes an entire arena, and it has
+ * a header just before the allocation pointing back to its predecessor's
+ * next member. Otherwise, we have to search pool for a.
+ */
+ if (size > pool->arenasize) {
+ ap = *PTR_TO_HEADER(pool, p);
+ a = *ap;
+ } else {
+ q = (jsuword)p + size;
+ q = JS_ARENA_ALIGN(pool, q);
+ ap = &pool->first.next;
+ while ((a = *ap) != NULL) {
+ JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+
+ if (a->avail == q) {
+ /*
+ * If a is consumed by the allocation at p, we can free it to
+ * the malloc heap.
+ */
+ if (a->base == (jsuword)p)
+ break;
+
+ /*
+ * We can't free a, but we can "retract" its avail cursor --
+ * whether there are others after it in pool.
+ */
+ a->avail = (jsuword)p;
+ return;
+ }
+ ap = &a->next;
+ }
+ }
+
+ /*
+ * At this point, a is doomed, so ensure that pool->current doesn't point
+ * at it. What's more, force future allocations to scavenge all arenas on
+ * pool, in case some have free space.
+ */
+ if (pool->current == a)
+ pool->current = &pool->first;
+
+ /*
+ * This is a non-LIFO deallocation, so take care to fix up a->next's back
+ * pointer in its header, if a->next is oversized.
+ */
+ *ap = b = a->next;
+ if (b && b->avail - b->base > pool->arenasize) {
+ JS_ASSERT(GET_HEADER(pool, b) == &a->next);
+ SET_HEADER(pool, b, ap);
+ }
+ JS_CLEAR_ARENA(a);
+ JS_COUNT_ARENA(pool,--);
+ free(a);
+}
+
+JS_PUBLIC_API(void)
+JS_FreeArenaPool(JSArenaPool *pool)
+{
+ FreeArenaList(pool, &pool->first, JS_FALSE);
+ COUNT(pool, ndeallocs);
+}
+
+JS_PUBLIC_API(void)
+JS_FinishArenaPool(JSArenaPool *pool)
+{
+ FreeArenaList(pool, &pool->first, JS_TRUE);
+#ifdef JS_ARENAMETER
+ {
+ JSArenaStats *stats, **statsp;
+
+ if (pool->stats.name)
+ free(pool->stats.name);
+ for (statsp = &arena_stats_list; (stats = *statsp) != 0;
+ statsp = &stats->next) {
+ if (stats == &pool->stats) {
+ *statsp = stats->next;
+ return;
+ }
+ }
+ }
+#endif
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaFinish()
+{
+ JSArena *a, *next;
+
+ JS_ACQUIRE_LOCK(arena_freelist_lock);
+ a = arena_freelist;
+ arena_freelist = NULL;
+ JS_RELEASE_LOCK(arena_freelist_lock);
+ for (; a; a = next) {
+ next = a->next;
+ free(a);
+ }
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaShutDown(void)
+{
+#ifdef JS_THREADSAFE
+ /* Must come through here once in the process's last thread! */
+ if (arena_freelist_lock) {
+ JS_DESTROY_LOCK(arena_freelist_lock);
+ arena_freelist_lock = NULL;
+ }
+#endif
+}
+
+#ifdef JS_ARENAMETER
+JS_PUBLIC_API(void)
+JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb)
+{
+ pool->stats.nallocs++;
+ pool->stats.nbytes += nb;
+ if (nb > pool->stats.maxalloc)
+ pool->stats.maxalloc = nb;
+ pool->stats.variance += nb * nb;
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr)
+{
+ pool->stats.ninplace++;
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr)
+{
+ pool->stats.ngrows++;
+ pool->stats.nbytes += incr;
+ pool->stats.variance -= size * size;
+ size += incr;
+ if (size > pool->stats.maxalloc)
+ pool->stats.maxalloc = size;
+ pool->stats.variance += size * size;
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaCountRelease(JSArenaPool *pool, char *mark)
+{
+ pool->stats.nreleases++;
+}
+
+JS_PUBLIC_API(void)
+JS_ArenaCountRetract(JSArenaPool *pool, char *mark)
+{
+ pool->stats.nfastrels++;
+}
+
+#include <math.h>
+#include <stdio.h>
+
+JS_PUBLIC_API(void)
+JS_DumpArenaStats(FILE *fp)
+{
+ JSArenaStats *stats;
+ uint32 nallocs, nbytes;
+ double mean, variance, sigma;
+
+ for (stats = arena_stats_list; stats; stats = stats->next) {
+ nallocs = stats->nallocs;
+ if (nallocs != 0) {
+ nbytes = stats->nbytes;
+ mean = (double)nbytes / nallocs;
+ variance = stats->variance * nallocs - nbytes * nbytes;
+ if (variance < 0 || nallocs == 1)
+ variance = 0;
+ else
+ variance /= nallocs * (nallocs - 1);
+ sigma = sqrt(variance);
+ } else {
+ mean = variance = sigma = 0;
+ }
+
+ fprintf(fp, "\n%s allocation statistics:\n", stats->name);
+ fprintf(fp, " number of arenas: %u\n", stats->narenas);
+ fprintf(fp, " number of allocations: %u\n", stats->nallocs);
+ fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims);
+ fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs);
+ fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs);
+ fprintf(fp, " number of allocation growths: %u\n", stats->ngrows);
+ fprintf(fp, " number of in-place growths: %u\n", stats->ninplace);
+ fprintf(fp, " number of realloc'ing growths: %u\n", stats->nreallocs);
+ fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
+ fprintf(fp, " number of fast releases: %u\n", stats->nfastrels);
+ fprintf(fp, " total bytes allocated: %u\n", stats->nbytes);
+ fprintf(fp, " mean allocation size: %g\n", mean);
+ fprintf(fp, " standard deviation: %g\n", sigma);
+ fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc);
+ }
+}
+#endif /* JS_ARENAMETER */
diff --git a/src/dom/js/jsarena.h b/src/dom/js/jsarena.h
new file mode 100644
index 000000000..e52398a1a
--- /dev/null
+++ b/src/dom/js/jsarena.h
@@ -0,0 +1,302 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsarena_h___
+#define jsarena_h___
+/*
+ * Lifetime-based fast allocation, inspired by much prior art, including
+ * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
+ * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
+ *
+ * Also supports LIFO allocation (JS_ARENA_MARK/JS_ARENA_RELEASE).
+ */
+#include <stdlib.h>
+#include "jstypes.h"
+#include "jscompat.h"
+
+JS_BEGIN_EXTERN_C
+
+typedef struct JSArena JSArena;
+typedef struct JSArenaPool JSArenaPool;
+
+struct JSArena {
+ JSArena *next; /* next arena for this lifetime */
+ jsuword base; /* aligned base address, follows this header */
+ jsuword limit; /* one beyond last byte in arena */
+ jsuword avail; /* points to next available byte */
+};
+
+#ifdef JS_ARENAMETER
+typedef struct JSArenaStats JSArenaStats;
+
+struct JSArenaStats {
+ JSArenaStats *next; /* next in arenaStats list */
+ char *name; /* name for debugging */
+ uint32 narenas; /* number of arenas in pool */
+ uint32 nallocs; /* number of JS_ARENA_ALLOCATE() calls */
+ uint32 nreclaims; /* number of reclaims from freeArenas */
+ uint32 nmallocs; /* number of malloc() calls */
+ uint32 ndeallocs; /* number of lifetime deallocations */
+ uint32 ngrows; /* number of JS_ARENA_GROW() calls */
+ uint32 ninplace; /* number of in-place growths */
+ uint32 nreallocs; /* number of arena grow extending reallocs */
+ uint32 nreleases; /* number of JS_ARENA_RELEASE() calls */
+ uint32 nfastrels; /* number of "fast path" releases */
+ size_t nbytes; /* total bytes allocated */
+ size_t maxalloc; /* maximum allocation size in bytes */
+ double variance; /* size variance accumulator */
+};
+#endif
+
+struct JSArenaPool {
+ JSArena first; /* first arena in pool list */
+ JSArena *current; /* arena from which to allocate space */
+ size_t arenasize; /* net exact size of a new arena */
+ jsuword mask; /* alignment mask (power-of-2 - 1) */
+#ifdef JS_ARENAMETER
+ JSArenaStats stats;
+#endif
+};
+
+/*
+ * If the including .c file uses only one power-of-2 alignment, it may define
+ * JS_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions
+ * per ALLOCATE and GROW.
+ */
+#ifdef JS_ARENA_CONST_ALIGN_MASK
+#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + JS_ARENA_CONST_ALIGN_MASK) \
+ & ~(jsuword)JS_ARENA_CONST_ALIGN_MASK)
+
+#define JS_INIT_ARENA_POOL(pool, name, size) \
+ JS_InitArenaPool(pool, name, size, JS_ARENA_CONST_ALIGN_MASK + 1)
+#else
+#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + (pool)->mask) & ~(pool)->mask)
+#endif
+
+#define JS_ARENA_ALLOCATE(p, pool, nb) \
+ JS_ARENA_ALLOCATE_CAST(p, void *, pool, nb)
+
+#define JS_ARENA_ALLOCATE_TYPE(p, type, pool) \
+ JS_ARENA_ALLOCATE_CAST(p, type *, pool, sizeof(type))
+
+#define JS_ARENA_ALLOCATE_CAST(p, type, pool, nb) \
+ JS_BEGIN_MACRO \
+ JSArena *_a = (pool)->current; \
+ size_t _nb = JS_ARENA_ALIGN(pool, nb); \
+ jsuword _p = _a->avail; \
+ jsuword _q = _p + _nb; \
+ JS_ASSERT(_q >= _p); \
+ if (_q > _a->limit) \
+ _p = (jsuword)JS_ArenaAllocate(pool, _nb); \
+ else \
+ _a->avail = _q; \
+ p = (type) _p; \
+ JS_ArenaCountAllocation(pool, nb); \
+ JS_END_MACRO
+
+#define JS_ARENA_GROW(p, pool, size, incr) \
+ JS_ARENA_GROW_CAST(p, void *, pool, size, incr)
+
+#define JS_ARENA_GROW_CAST(p, type, pool, size, incr) \
+ JS_BEGIN_MACRO \
+ JSArena *_a = (pool)->current; \
+ if (_a->avail == (jsuword)(p) + JS_ARENA_ALIGN(pool, size)) { \
+ size_t _nb = (size) + (incr); \
+ jsuword _q = (jsuword)(p) + JS_ARENA_ALIGN(pool, _nb); \
+ if (_q <= _a->limit) { \
+ _a->avail = _q; \
+ JS_ArenaCountInplaceGrowth(pool, size, incr); \
+ } else if ((jsuword)(p) == _a->base) { \
+ p = (type) JS_ArenaRealloc(pool, p, size, incr); \
+ } else { \
+ p = (type) JS_ArenaGrow(pool, p, size, incr); \
+ } \
+ } else { \
+ p = (type) JS_ArenaGrow(pool, p, size, incr); \
+ } \
+ JS_ArenaCountGrowth(pool, size, incr); \
+ JS_END_MACRO
+
+#define JS_ARENA_MARK(pool) ((void *) (pool)->current->avail)
+#define JS_UPTRDIFF(p,q) ((jsuword)(p) - (jsuword)(q))
+
+#ifdef DEBUG
+#define JS_FREE_PATTERN 0xDA
+#define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \
+ memset((void*)(a)->avail, JS_FREE_PATTERN, \
+ (a)->limit - (a)->avail))
+#define JS_CLEAR_ARENA(a) memset((void*)(a), JS_FREE_PATTERN, \
+ (a)->limit - (jsuword)(a))
+#else
+#define JS_CLEAR_UNUSED(a) /* nothing */
+#define JS_CLEAR_ARENA(a) /* nothing */
+#endif
+
+#define JS_ARENA_RELEASE(pool, mark) \
+ JS_BEGIN_MACRO \
+ char *_m = (char *)(mark); \
+ JSArena *_a = (pool)->current; \
+ if (_a != &(pool)->first && \
+ JS_UPTRDIFF(_m, _a->base) <= JS_UPTRDIFF(_a->avail, _a->base)) { \
+ _a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m); \
+ JS_ASSERT(_a->avail <= _a->limit); \
+ JS_CLEAR_UNUSED(_a); \
+ JS_ArenaCountRetract(pool, _m); \
+ } else { \
+ JS_ArenaRelease(pool, _m); \
+ } \
+ JS_ArenaCountRelease(pool, _m); \
+ JS_END_MACRO
+
+#ifdef JS_ARENAMETER
+#define JS_COUNT_ARENA(pool,op) ((pool)->stats.narenas op)
+#else
+#define JS_COUNT_ARENA(pool,op)
+#endif
+
+#define JS_ARENA_DESTROY(pool, a, pnext) \
+ JS_BEGIN_MACRO \
+ JS_COUNT_ARENA(pool,--); \
+ if ((pool)->current == (a)) (pool)->current = &(pool)->first; \
+ *(pnext) = (a)->next; \
+ JS_CLEAR_ARENA(a); \
+ free(a); \
+ (a) = NULL; \
+ JS_END_MACRO
+
+/*
+ * Initialize an arena pool with the given name for debugging and metering,
+ * with a minimum size per arena of size bytes.
+ */
+extern JS_PUBLIC_API(void)
+JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size,
+ size_t align);
+
+/*
+ * Free the arenas in pool. The user may continue to allocate from pool
+ * after calling this function. There is no need to call JS_InitArenaPool()
+ * again unless JS_FinishArenaPool(pool) has been called.
+ */
+extern JS_PUBLIC_API(void)
+JS_FreeArenaPool(JSArenaPool *pool);
+
+/*
+ * Free the arenas in pool and finish using it altogether.
+ */
+extern JS_PUBLIC_API(void)
+JS_FinishArenaPool(JSArenaPool *pool);
+
+/*
+ * Finish using arenas, freeing all memory associated with them except for
+ * any locks needed for thread safety.
+ */
+extern JS_PUBLIC_API(void)
+JS_ArenaFinish(void);
+
+/*
+ * Free any locks or other memory needed for thread safety, just before
+ * shutting down. At that point, we must be called by a single thread.
+ *
+ * After shutting down, the next thread to call JS_InitArenaPool must not
+ * race with any other thread. Once a pool has been initialized, threads
+ * may safely call jsarena.c functions on thread-local pools. The upshot
+ * is that pools are per-thread, but the underlying global freelist is
+ * thread-safe, provided that both the first pool initialization and the
+ * shut-down call are single-threaded.
+ */
+extern JS_PUBLIC_API(void)
+JS_ArenaShutDown(void);
+
+/*
+ * Friend functions used by the JS_ARENA_*() macros.
+ */
+extern JS_PUBLIC_API(void *)
+JS_ArenaAllocate(JSArenaPool *pool, size_t nb);
+
+extern JS_PUBLIC_API(void *)
+JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr);
+
+extern JS_PUBLIC_API(void *)
+JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr);
+
+extern JS_PUBLIC_API(void)
+JS_ArenaRelease(JSArenaPool *pool, char *mark);
+
+/*
+ * Function to be used directly when an allocation has likely grown to consume
+ * an entire JSArena, in which case the arena is returned to the malloc heap.
+ */
+extern JS_PUBLIC_API(void)
+JS_ArenaFreeAllocation(JSArenaPool *pool, void *p, size_t size);
+
+#ifdef JS_ARENAMETER
+
+#include <stdio.h>
+
+extern JS_PUBLIC_API(void)
+JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb);
+
+extern JS_PUBLIC_API(void)
+JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr);
+
+extern JS_PUBLIC_API(void)
+JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr);
+
+extern JS_PUBLIC_API(void)
+JS_ArenaCountRelease(JSArenaPool *pool, char *mark);
+
+extern JS_PUBLIC_API(void)
+JS_ArenaCountRetract(JSArenaPool *pool, char *mark);
+
+extern JS_PUBLIC_API(void)
+JS_DumpArenaStats(FILE *fp);
+
+#else /* !JS_ARENAMETER */
+
+#define JS_ArenaCountAllocation(ap, nb) /* nothing */
+#define JS_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */
+#define JS_ArenaCountGrowth(ap, size, incr) /* nothing */
+#define JS_ArenaCountRelease(ap, mark) /* nothing */
+#define JS_ArenaCountRetract(ap, mark) /* nothing */
+
+#endif /* !JS_ARENAMETER */
+
+JS_END_EXTERN_C
+
+#endif /* jsarena_h___ */
diff --git a/src/dom/js/jsarray.c b/src/dom/js/jsarray.c
new file mode 100644
index 000000000..250c67557
--- /dev/null
+++ b/src/dom/js/jsarray.c
@@ -0,0 +1,1429 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS array class.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsstr.h"
+
+/* 2^32 - 1 as a number and a string */
+#define MAXINDEX 4294967295u
+#define MAXSTR "4294967295"
+
+/*
+ * Determine if the id represents an array index.
+ *
+ * An id is an array index according to ECMA by (15.4):
+ *
+ * "Array objects give special treatment to a certain class of property names.
+ * A property name P (in the form of a string value) is an array index if and
+ * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
+ * to 2^32-1."
+ *
+ * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id)
+ * except that by using signed 32-bit integers we miss the top half of the
+ * valid range. This function checks the string representation itself; note
+ * that calling a standard conversion routine might allow strings such as
+ * "08" or "4.0" as array indices, which they are not.
+ */
+static JSBool
+IdIsIndex(jsid id, jsuint *indexp)
+{
+ JSString *str;
+ jschar *cp;
+
+ if (JSVAL_IS_INT(id)) {
+ jsint i;
+ i = JSVAL_TO_INT(id);
+ if (i < 0)
+ return JS_FALSE;
+ *indexp = (jsuint)i;
+ return JS_TRUE;
+ }
+
+ /* It must be a string. */
+ str = JSVAL_TO_STRING(id);
+ cp = JSSTRING_CHARS(str);
+ if (JS7_ISDEC(*cp) && JSSTRING_LENGTH(str) < sizeof(MAXSTR)) {
+ jsuint index = JS7_UNDEC(*cp++);
+ jsuint oldIndex = 0;
+ jsuint c = 0;
+ if (index != 0) {
+ while (JS7_ISDEC(*cp)) {
+ oldIndex = index;
+ c = JS7_UNDEC(*cp);
+ index = 10*index + c;
+ cp++;
+ }
+ }
+ /* Make sure all characters were consumed and that it couldn't
+ * have overflowed.
+ */
+ if (*cp == 0 &&
+ (oldIndex < (MAXINDEX / 10) ||
+ (oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
+ {
+ *indexp = index;
+ return JS_TRUE;
+ }
+ }
+ return JS_FALSE;
+}
+
+static JSBool
+ValueIsLength(JSContext *cx, jsval v, jsuint *lengthp)
+{
+ jsint i;
+ jsdouble d;
+
+ if (JSVAL_IS_INT(v)) {
+ i = JSVAL_TO_INT(v);
+ if (i < 0) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_ARRAY_LENGTH);
+ return JS_FALSE;
+ }
+ *lengthp = (jsuint) i;
+ return JS_TRUE;
+ }
+
+ if (!js_ValueToNumber(cx, v, &d)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_ARRAY_LENGTH);
+ return JS_FALSE;
+ }
+ if (!js_DoubleToECMAUint32(cx, d, (uint32 *)lengthp)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_ARRAY_LENGTH);
+ return JS_FALSE;
+ }
+ if (JSDOUBLE_IS_NaN(d) || d != *lengthp) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_ARRAY_LENGTH);
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
+{
+ jsid id;
+ jsint i;
+ jsval v;
+
+ id = (jsid) cx->runtime->atomState.lengthAtom;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+
+ /* Short-circuit, because js_ValueToECMAUint32 fails when
+ * called during init time.
+ */
+ if (JSVAL_IS_INT(v)) {
+ i = JSVAL_TO_INT(v);
+ /* jsuint cast does ToUint32. */
+ *lengthp = (jsuint)i;
+ return JS_TRUE;
+ }
+ return js_ValueToECMAUint32(cx, v, (uint32 *)lengthp);
+}
+
+static JSBool
+IndexToValue(JSContext *cx, jsuint length, jsval *vp)
+{
+ if (length <= JSVAL_INT_MAX) {
+ *vp = INT_TO_JSVAL(length);
+ return JS_TRUE;
+ }
+ return js_NewDoubleValue(cx, (jsdouble)length, vp);
+}
+
+static JSBool
+IndexToId(JSContext *cx, jsuint length, jsid *idp)
+{
+ JSString *str;
+ JSAtom *atom;
+
+ if (length <= JSVAL_INT_MAX) {
+ *idp = (jsid) INT_TO_JSVAL(length);
+ } else {
+ str = js_NumberToString(cx, (jsdouble)length);
+ if (!str)
+ return JS_FALSE;
+ atom = js_AtomizeString(cx, str, 0);
+ if (!atom)
+ return JS_FALSE;
+ *idp = (jsid)atom;
+
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length)
+{
+ jsval v;
+ jsid id;
+
+ if (!IndexToValue(cx, length, &v))
+ return JS_FALSE;
+ id = (jsid) cx->runtime->atomState.lengthAtom;
+ return OBJ_SET_PROPERTY(cx, obj, id, &v);
+}
+
+JSBool
+js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
+{
+ JSErrorReporter older;
+ jsid id;
+ JSBool ok;
+ jsval v;
+
+ older = JS_SetErrorReporter(cx, NULL);
+ id = (jsid) cx->runtime->atomState.lengthAtom;
+ ok = OBJ_GET_PROPERTY(cx, obj, id, &v);
+ JS_SetErrorReporter(cx, older);
+ if (!ok)
+ return JS_FALSE;
+ return ValueIsLength(cx, v, lengthp);
+}
+
+/*
+ * This get function is specific to Array.prototype.length and other array
+ * instance length properties. It calls back through the class get function
+ * in case some magic happens there (see call_getProperty in jsfun.c).
+ */
+static JSBool
+array_length_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ return OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, id, vp);
+}
+
+static JSBool
+array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsuint newlen, oldlen, slot;
+ jsid id2;
+ jsval junk;
+
+ if (!ValueIsLength(cx, *vp, &newlen))
+ return JS_FALSE;
+ if (!js_GetLengthProperty(cx, obj, &oldlen))
+ return JS_FALSE;
+ slot = oldlen;
+ while (slot > newlen) {
+ --slot;
+ if (!IndexToId(cx, slot, &id2))
+ return JS_FALSE;
+ if (!OBJ_DELETE_PROPERTY(cx, obj, id2, &junk))
+ return JS_FALSE;
+ }
+ return IndexToValue(cx, newlen, vp);
+}
+
+static JSBool
+array_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsuint index, length;
+
+ if (!(IdIsIndex(id, &index)))
+ return JS_TRUE;
+ if (!js_GetLengthProperty(cx, obj, &length))
+ return JS_FALSE;
+ if (index >= length) {
+ length = index + 1;
+ return js_SetLengthProperty(cx, obj, length);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+array_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+{
+ jsuint length;
+
+ if (cx->version == JSVERSION_1_2) {
+ if (!js_GetLengthProperty(cx, obj, &length))
+ return JS_FALSE;
+ switch (type) {
+ case JSTYPE_NUMBER:
+ return IndexToValue(cx, length, vp);
+ case JSTYPE_BOOLEAN:
+ *vp = BOOLEAN_TO_JSVAL(length > 0);
+ return JS_TRUE;
+ default:
+ return JS_TRUE;
+ }
+ }
+ return js_TryValueOf(cx, obj, type, vp);
+}
+
+JSClass js_ArrayClass = {
+ "Array",
+ 0,
+ array_addProperty, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, array_convert, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+static JSBool
+array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
+ jsval *rval, JSBool localeString)
+{
+ JSBool ok;
+ jsval v;
+ jsuint length, index;
+ jschar *chars, *ochars;
+ size_t nchars, growth, seplen, tmplen;
+ const jschar *sepstr;
+ JSString *str;
+ JSHashEntry *he;
+ JSObject *obj2;
+
+ ok = js_GetLengthProperty(cx, obj, &length);
+ if (!ok)
+ return JS_FALSE;
+ ok = JS_TRUE;
+
+ he = js_EnterSharpObject(cx, obj, NULL, &chars);
+ if (!he)
+ return JS_FALSE;
+ if (literalize) {
+ if (IS_SHARP(he)) {
+#if JS_HAS_SHARP_VARS
+ nchars = js_strlen(chars);
+#else
+ chars[0] = '[';
+ chars[1] = ']';
+ chars[2] = 0;
+ nchars = 2;
+#endif
+ goto make_string;
+ }
+
+ /*
+ * Allocate 1 + 3 + 1 for "[", the worst-case closing ", ]", and the
+ * terminating 0.
+ */
+ growth = (1 + 3 + 1) * sizeof(jschar);
+ if (!chars) {
+ nchars = 0;
+ chars = (jschar *) malloc(growth);
+ if (!chars)
+ goto done;
+ } else {
+ MAKE_SHARP(he);
+ nchars = js_strlen(chars);
+ chars = (jschar *)
+ realloc((ochars = chars), nchars * sizeof(jschar) + growth);
+ if (!chars) {
+ free(ochars);
+ goto done;
+ }
+ }
+ chars[nchars++] = '[';
+ } else {
+ /*
+ * Free any sharp variable definition in chars. Normally, we would
+ * MAKE_SHARP(he) so that only the first sharp variable annotation is
+ * a definition, and all the rest are references, but in the current
+ * case of (!literalize), we don't need chars at all.
+ */
+ if (chars)
+ JS_free(cx, chars);
+ chars = NULL;
+ nchars = 0;
+
+ /* Return the empty string on a cycle as well as on empty join. */
+ if (IS_BUSY(he) || length == 0) {
+ js_LeaveSharpObject(cx, NULL);
+ *rval = JS_GetEmptyStringValue(cx);
+ return ok;
+ }
+
+ /* Flag he as BUSY so we can distinguish a cycle from a join-point. */
+ MAKE_BUSY(he);
+ }
+ sepstr = NULL;
+ seplen = JSSTRING_LENGTH(sep);
+
+ v = JSVAL_NULL;
+ for (index = 0; index < length; index++) {
+ ok = JS_GetElement(cx, obj, index, &v);
+ if (!ok)
+ goto done;
+
+ if (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v)) {
+ str = cx->runtime->emptyString;
+ } else {
+ if (localeString) {
+ if (!js_ValueToObject(cx, v, &obj2) ||
+ !js_TryMethod(cx, obj2,
+ cx->runtime->atomState.toLocaleStringAtom,
+ 0, NULL, &v)) {
+ str = NULL;
+ } else {
+ str = js_ValueToString(cx, v);
+ }
+ } else {
+ str = (literalize ? js_ValueToSource : js_ValueToString)(cx, v);
+ }
+ if (!str) {
+ ok = JS_FALSE;
+ goto done;
+ }
+ }
+
+ /* Allocate 3 + 1 at end for ", ", closing bracket, and zero. */
+ growth = (nchars + (sepstr ? seplen : 0) +
+ JSSTRING_LENGTH(str) +
+ 3 + 1) * sizeof(jschar);
+ if (!chars) {
+ chars = (jschar *) malloc(growth);
+ if (!chars)
+ goto done;
+ } else {
+ chars = (jschar *) realloc((ochars = chars), growth);
+ if (!chars) {
+ free(ochars);
+ goto done;
+ }
+ }
+
+ if (sepstr) {
+ js_strncpy(&chars[nchars], sepstr, seplen);
+ nchars += seplen;
+ }
+ sepstr = JSSTRING_CHARS(sep);
+
+ tmplen = JSSTRING_LENGTH(str);
+ js_strncpy(&chars[nchars], JSSTRING_CHARS(str), tmplen);
+ nchars += tmplen;
+ }
+
+ done:
+ if (literalize) {
+ if (chars) {
+ if (JSVAL_IS_VOID(v)) {
+ chars[nchars++] = ',';
+ chars[nchars++] = ' ';
+ }
+ chars[nchars++] = ']';
+ }
+ } else {
+ CLEAR_BUSY(he);
+ }
+ js_LeaveSharpObject(cx, NULL);
+ if (!ok) {
+ if (chars)
+ free(chars);
+ return ok;
+ }
+
+ make_string:
+ if (!chars) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ chars[nchars] = 0;
+ str = js_NewString(cx, chars, nchars, 0);
+ if (!str) {
+ free(chars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static jschar comma_space_ucstr[] = {',', ' ', 0};
+static jschar comma_ucstr[] = {',', 0};
+static JSString comma_space = {2, comma_space_ucstr};
+static JSString comma = {1, comma_ucstr};
+
+#if JS_HAS_TOSOURCE
+static JSBool
+array_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ return array_join_sub(cx, obj, &comma_space, JS_TRUE, rval, JS_FALSE);
+}
+#endif
+
+static JSBool
+array_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSBool literalize;
+
+ /*
+ * JS1.2 arrays convert to array literals, with a comma followed by a space
+ * between each element.
+ */
+ literalize = (cx->version == JSVERSION_1_2);
+ return array_join_sub(cx, obj, literalize ? &comma_space : &comma,
+ literalize, rval, JS_FALSE);
+}
+
+static JSBool
+array_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ /*
+ * Passing comma here as the separator. Need a way to get a
+ * locale-specific version.
+ */
+ return array_join_sub(cx, obj, &comma, JS_FALSE, rval, JS_TRUE);
+}
+
+static JSBool
+InitArrayElements(JSContext *cx, JSObject *obj, jsuint length, jsval *vector)
+{
+ jsuint index;
+ jsid id;
+
+ for (index = 0; index < length; index++) {
+ if (!IndexToId(cx, index, &id))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id, &vector[index]))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector)
+{
+ jsval v;
+ jsid id;
+
+ if (!IndexToValue(cx, length, &v))
+ return JS_FALSE;
+ id = (jsid) cx->runtime->atomState.lengthAtom;
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, id, v,
+ array_length_getter, array_length_setter,
+ JSPROP_PERMANENT,
+ NULL)) {
+ return JS_FALSE;
+ }
+ if (!vector)
+ return JS_TRUE;
+ return InitArrayElements(cx, obj, length, vector);
+}
+
+#if JS_HAS_SOME_PERL_FUN
+/*
+ * Perl-inspired join, reverse, and sort.
+ */
+static JSBool
+array_join(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+
+ if (JSVAL_IS_VOID(argv[0]))
+ return array_join_sub(cx, obj, &comma, JS_FALSE, rval, JS_FALSE);
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str);
+ return array_join_sub(cx, obj, str, JS_FALSE, rval, JS_FALSE);
+}
+
+static JSBool
+array_reverse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsuint len, half, i;
+ jsid id, id2;
+ jsval v, v2;
+
+ if (!js_GetLengthProperty(cx, obj, &len))
+ return JS_FALSE;
+
+ half = len / 2;
+ for (i = 0; i < half; i++) {
+ if (!IndexToId(cx, i, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, len - i - 1, &id2))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id2, &v2))
+ return JS_FALSE;
+
+#if JS_HAS_SPARSE_ARRAYS
+ /* This part isn't done yet. */
+
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ OBJ_DELETE_PROPERTY(cx, obj, id2, &v); /* v is junk. */
+ continue;
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+#endif
+
+ if (!OBJ_SET_PROPERTY(cx, obj, id, &v2))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
+ return JS_FALSE;
+ }
+
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+typedef struct HSortArgs {
+ void *vec;
+ size_t elsize;
+ void *pivot;
+ JSComparator cmp;
+ void *arg;
+ JSBool fastcopy;
+} HSortArgs;
+
+static int
+sort_compare(const void *a, const void *b, void *arg);
+
+static int
+sort_compare_strings(const void *a, const void *b, void *arg);
+
+static void
+HeapSortHelper(JSBool building, HSortArgs *hsa, size_t lo, size_t hi)
+{
+ void *pivot, *vec, *vec2, *arg, *a, *b;
+ size_t elsize;
+ JSComparator cmp;
+ JSBool fastcopy;
+ size_t j, hiDiv2;
+
+ pivot = hsa->pivot;
+ vec = hsa->vec;
+ elsize = hsa->elsize;
+ vec2 = (char *)vec - 2 * elsize;
+ cmp = hsa->cmp;
+ arg = hsa->arg;
+
+ fastcopy = hsa->fastcopy;
+#define MEMCPY(p,q,n) \
+ (fastcopy ? (void)(*(jsval*)(p) = *(jsval*)(q)) : (void)memcpy(p, q, n))
+
+ if (lo == 1) {
+ j = 2;
+ b = (char *)vec + elsize;
+ if (j < hi && cmp(vec, b, arg) < 0)
+ j++;
+ a = (char *)vec + (hi - 1) * elsize;
+ b = (char *)vec2 + j * elsize;
+
+ /*
+ * During sorting phase b points to a member of heap that cannot be
+ * bigger then biggest of vec[0] and vec[1], and cmp(a, b, arg) <= 0
+ * always holds.
+ */
+ if ((building || hi == 2) && cmp(a, b, arg) >= 0)
+ return;
+
+ MEMCPY(pivot, a, elsize);
+ MEMCPY(a, b, elsize);
+ lo = j;
+ } else {
+ a = (char *)vec2 + lo * elsize;
+ MEMCPY(pivot, a, elsize);
+ }
+
+ hiDiv2 = hi/2;
+ while (lo <= hiDiv2) {
+ j = lo + lo;
+ a = (char *)vec2 + j * elsize;
+ b = (char *)vec + (j - 1) * elsize;
+ if (j < hi && cmp(a, b, arg) < 0)
+ j++;
+ b = (char *)vec2 + j * elsize;
+ if (cmp(pivot, b, arg) >= 0)
+ break;
+
+ a = (char *)vec2 + lo * elsize;
+ MEMCPY(a, b, elsize);
+ lo = j;
+ }
+
+ a = (char *)vec2 + lo * elsize;
+ MEMCPY(a, pivot, elsize);
+#undef MEMCPY
+}
+
+JSBool
+js_HeapSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, void *arg)
+{
+ void *pivot;
+ HSortArgs hsa;
+ size_t i;
+
+ pivot = malloc(elsize);
+ if (!pivot)
+ return JS_FALSE;
+ hsa.vec = vec;
+ hsa.elsize = elsize;
+ hsa.pivot = pivot;
+ hsa.cmp = cmp;
+ hsa.arg = arg;
+ hsa.fastcopy = (cmp == sort_compare || cmp == sort_compare_strings);
+
+ for (i = nel/2; i != 0; i--)
+ HeapSortHelper(JS_TRUE, &hsa, i, nel);
+ while (nel > 2)
+ HeapSortHelper(JS_FALSE, &hsa, 1, --nel);
+
+ free(pivot);
+ return JS_TRUE;
+}
+
+typedef struct CompareArgs {
+ JSContext *context;
+ jsval fval;
+ JSBool status;
+} CompareArgs;
+
+static int
+sort_compare(const void *a, const void *b, void *arg)
+{
+ jsval av = *(const jsval *)a, bv = *(const jsval *)b;
+ CompareArgs *ca = (CompareArgs *) arg;
+ JSContext *cx = ca->context;
+ jsdouble cmp = -1;
+ jsval fval, argv[2], rval;
+ JSBool ok;
+
+ fval = ca->fval;
+ if (fval == JSVAL_NULL) {
+ JSString *astr, *bstr;
+
+ if (av == bv) {
+ cmp = 0;
+ } else if (av == JSVAL_VOID || bv == JSVAL_VOID) {
+ /* Put undefined properties at the end. */
+ cmp = (av == JSVAL_VOID) ? 1 : -1;
+ } else if ((astr = js_ValueToString(cx, av)) != NULL &&
+ (bstr = js_ValueToString(cx, bv)) != NULL) {
+ cmp = js_CompareStrings(astr, bstr);
+ } else {
+ ca->status = JS_FALSE;
+ }
+ } else {
+ argv[0] = av;
+ argv[1] = bv;
+ ok = js_InternalCall(cx,
+ OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fval)),
+ fval, 2, argv, &rval);
+ if (ok) {
+ ok = js_ValueToNumber(cx, rval, &cmp);
+ /* Clamp cmp to -1, 0, 1. */
+ if (JSDOUBLE_IS_NaN(cmp)) {
+ /* XXX report some kind of error here? ECMA talks about
+ * 'consistent compare functions' that don't return NaN, but is
+ * silent about what the result should be. So we currently
+ * ignore it.
+ */
+ cmp = 0;
+ } else if (cmp != 0) {
+ cmp = cmp > 0 ? 1 : -1;
+ }
+ } else {
+ ca->status = ok;
+ }
+ }
+ return (int)cmp;
+}
+
+static int
+sort_compare_strings(const void *a, const void *b, void *arg)
+{
+ jsval av = *(const jsval *)a, bv = *(const jsval *)b;
+
+ return (int) js_CompareStrings(JSVAL_TO_STRING(av), JSVAL_TO_STRING(bv));
+}
+
+/* XXXmccabe do the sort helper functions need to take int? (Or can we claim
+ * that 2^32 * 32 is too large to worry about?) Something dumps when I change
+ * to unsigned int; is qsort using -1 as a fencepost?
+ */
+static JSBool
+array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval fval;
+ CompareArgs ca;
+ jsuint len, newlen, i;
+ jsval *vec;
+ jsid id;
+ size_t nbytes;
+
+ /*
+ * Optimize the default compare function case if all of obj's elements
+ * have values of type string.
+ */
+ JSBool all_strings;
+
+ if (argc > 0) {
+ if (JSVAL_IS_PRIMITIVE(argv[0])) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_SORT_ARG);
+ return JS_FALSE;
+ }
+ fval = argv[0];
+ all_strings = JS_FALSE; /* non-default compare function */
+ } else {
+ fval = JSVAL_NULL;
+ all_strings = JS_TRUE; /* check for all string values */
+ }
+
+ if (!js_GetLengthProperty(cx, obj, &len))
+ return JS_FALSE;
+ if (len == 0) {
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+ }
+
+ /*
+ * Test for size_t overflow, which could lead to indexing beyond the end
+ * of the malloc'd vector.
+ */
+ nbytes = len * sizeof(jsval);
+ if (nbytes != (double) len * sizeof(jsval)) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ vec = (jsval *) JS_malloc(cx, nbytes);
+ if (!vec)
+ return JS_FALSE;
+
+#if JS_HAS_SPARSE_ARRAYS
+ newlen = 0;
+#else
+ newlen = len;
+#endif
+
+ for (i = 0; i < len; i++) {
+ ca.status = IndexToId(cx, i, &id);
+ if (!ca.status)
+ goto out;
+#if JS_HAS_SPARSE_ARRAYS
+ {
+ JSObject *obj2;
+ JSProperty *prop;
+ ca.status = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
+ if (!ca.status)
+ goto out;
+ if (!prop) {
+ vec[i] = JSVAL_VOID;
+ continue;
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ newlen++;
+ }
+#endif
+ ca.status = OBJ_GET_PROPERTY(cx, obj, id, &vec[i]);
+ if (!ca.status)
+ goto out;
+
+ /* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */
+ all_strings &= JSVAL_IS_STRING(vec[i]);
+ }
+
+ ca.context = cx;
+ ca.fval = fval;
+ ca.status = JS_TRUE;
+ if (!js_HeapSort(vec, (size_t) len, sizeof(jsval),
+ all_strings ? sort_compare_strings : sort_compare,
+ &ca)) {
+ JS_ReportOutOfMemory(cx);
+ ca.status = JS_FALSE;
+ }
+
+ if (ca.status) {
+ ca.status = InitArrayElements(cx, obj, newlen, vec);
+ if (ca.status)
+ *rval = OBJECT_TO_JSVAL(obj);
+#if JS_HAS_SPARSE_ARRAYS
+ /* set length of newly-created array object to old length. */
+ if (ca.status && newlen < len) {
+ ca.status = js_SetLengthProperty(cx, obj, len);
+
+ /* Delete any leftover properties greater than newlen. */
+ while (ca.status && newlen < len) {
+ jsval junk;
+
+ ca.status = !IndexToId(cx, newlen, &id) ||
+ !OBJ_DELETE_PROPERTY(cx, obj, id, &junk);
+ newlen++;
+ }
+ }
+#endif
+ }
+
+out:
+ if (vec)
+ JS_free(cx, vec);
+ return ca.status;
+}
+#endif /* JS_HAS_SOME_PERL_FUN */
+
+#if JS_HAS_MORE_PERL_FUN
+/*
+ * Perl-inspired push, pop, shift, unshift, and splice methods.
+ */
+static JSBool
+array_push(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsuint length;
+ uintN i;
+ jsid id;
+
+ if (!js_GetLengthProperty(cx, obj, &length))
+ return JS_FALSE;
+ for (i = 0; i < argc; i++) {
+ if (!IndexToId(cx, length + i, &id))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id, &argv[i]))
+ return JS_FALSE;
+ }
+
+ /*
+ * If JS1.2, follow Perl4 by returning the last thing pushed. Otherwise,
+ * return the new array length.
+ */
+ length += argc;
+ if (cx->version == JSVERSION_1_2) {
+ *rval = argc ? argv[argc-1] : JSVAL_VOID;
+ } else {
+ if (!IndexToValue(cx, length, rval))
+ return JS_FALSE;
+ }
+ return js_SetLengthProperty(cx, obj, length);
+}
+
+static JSBool
+array_pop(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsuint index;
+ jsid id;
+ jsval junk;
+
+ if (!js_GetLengthProperty(cx, obj, &index))
+ return JS_FALSE;
+ if (index > 0) {
+ index--;
+ if (!IndexToId(cx, index, &id))
+ return JS_FALSE;
+
+ /* Get the to-be-deleted property's value into rval. */
+ if (!OBJ_GET_PROPERTY(cx, obj, id, rval))
+ return JS_FALSE;
+
+ if (!OBJ_DELETE_PROPERTY(cx, obj, id, &junk))
+ return JS_FALSE;
+ }
+ return js_SetLengthProperty(cx, obj, index);
+}
+
+static JSBool
+array_shift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsuint length, i;
+ jsid id, id2;
+ jsval v, junk;
+
+ if (!js_GetLengthProperty(cx, obj, &length))
+ return JS_FALSE;
+ if (length > 0) {
+ length--;
+ id = JSVAL_ZERO;
+
+ /* Get the to-be-deleted property's value into rval ASAP. */
+ if (!OBJ_GET_PROPERTY(cx, obj, id, rval))
+ return JS_FALSE;
+
+ /*
+ * Slide down the array above the first element.
+ */
+ if (length > 0) {
+ for (i = 1; i <= length; i++) {
+ if (!IndexToId(cx, i, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, i - 1, &id2))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
+ return JS_FALSE;
+ }
+ }
+
+ /* Delete the only or last element. */
+ if (!OBJ_DELETE_PROPERTY(cx, obj, id, &junk))
+ return JS_FALSE;
+ }
+ return js_SetLengthProperty(cx, obj, length);
+}
+
+static JSBool
+array_unshift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsuint length, last;
+ uintN i;
+ jsid id, id2;
+ jsval v;
+#if JS_HAS_SPARSE_ARRAYS
+ JSObject *obj2;
+ JSProperty *prop;
+#endif
+
+ if (!js_GetLengthProperty(cx, obj, &length))
+ return JS_FALSE;
+ if (argc > 0) {
+ /* Slide up the array to make room for argc at the bottom. */
+ if (length > 0) {
+ last = length;
+ while (last--) {
+ if (!IndexToId(cx, last, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, last + argc, &id2))
+ return JS_FALSE;
+#if JS_HAS_SPARSE_ARRAYS
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ OBJ_DELETE_PROPERTY(cx, obj, id2, &v); /* v is junk. */
+ continue;
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+#endif
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
+ return JS_FALSE;
+ }
+ }
+
+ /* Copy from argv to the bottom of the array. */
+ for (i = 0; i < argc; i++) {
+ if (!IndexToId(cx, i, &id))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id, &argv[i]))
+ return JS_FALSE;
+ }
+
+ /* Follow Perl by returning the new array length. */
+ length += argc;
+ if (!js_SetLengthProperty(cx, obj, length))
+ return JS_FALSE;
+ }
+ return IndexToValue(cx, length, rval);
+}
+
+static JSBool
+array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsuint length, begin, end, count, delta, last;
+ uintN i;
+ jsdouble d;
+ jsid id, id2;
+ jsval v;
+ JSObject *obj2;
+
+ /* Nothing to do if no args. Otherwise lock and load length. */
+ if (argc == 0)
+ return JS_TRUE;
+ if (!js_GetLengthProperty(cx, obj, &length))
+ return JS_FALSE;
+
+ /* Convert the first argument into a starting index. */
+ if (!js_ValueToNumber(cx, *argv, &d))
+ return JS_FALSE;
+ d = js_DoubleToInteger(d);
+ if (d < 0) {
+ d += length;
+ if (d < 0)
+ d = 0;
+ } else if (d > length) {
+ d = length;
+ }
+ begin = (jsuint)d; /* d has been clamped to uint32 */
+ argc--;
+ argv++;
+
+ /* Convert the second argument from a count into a fencepost index. */
+ delta = length - begin;
+ if (argc == 0) {
+ count = delta;
+ end = length;
+ } else {
+ if (!js_ValueToNumber(cx, *argv, &d))
+ return JS_FALSE;
+ d = js_DoubleToInteger(d);
+ if (d < 0)
+ d = 0;
+ else if (d > delta)
+ d = delta;
+ count = (jsuint)d;
+ end = begin + count;
+ argc--;
+ argv++;
+ }
+
+ if (count == 1 && cx->version == JSVERSION_1_2) {
+ /*
+ * JS lacks "list context", whereby in Perl one turns the single
+ * scalar that's spliced out into an array just by assigning it to
+ * @single instead of $single, or by using it as Perl push's first
+ * argument, for instance.
+ *
+ * JS1.2 emulated Perl too closely and returned a non-Array for
+ * the single-splice-out case, requiring callers to test and wrap
+ * in [] if necessary. So JS1.3, default, and other versions all
+ * return an array of length 1 for uniformity.
+ */
+ if (!IndexToId(cx, begin, &id))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, rval))
+ return JS_FALSE;
+ } else {
+ if (cx->version != JSVERSION_1_2 || count > 0) {
+ /*
+ * Create a new array value to return. Our ECMA v2 proposal specs
+ * that splice always returns an array value, even when given no
+ * arguments. We think this is best because it eliminates the need
+ * for callers to do an extra test to handle the empty splice case.
+ */
+ obj2 = js_NewArrayObject(cx, 0, NULL);
+ if (!obj2)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj2);
+
+ /* If there are elements to remove, put them into the return value. */
+ if (count > 0) {
+ for (last = begin; last < end; last++) {
+ if (!IndexToId(cx, last, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, last - begin, &id2))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj2, id2, &v))
+ return JS_FALSE;
+ }
+ }
+ }
+ }
+
+ /* Find the direction (up or down) to copy and make way for argv. */
+ if (argc > count) {
+ delta = (jsuint)argc - count;
+ last = length;
+ /* (uint) end could be 0, so can't use vanilla >= test */
+ while (last-- > end) {
+ if (!IndexToId(cx, last, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, last + delta, &id2))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
+ return JS_FALSE;
+ }
+ length += delta;
+ } else if (argc < count) {
+ delta = count - (jsuint)argc;
+ for (last = end; last < length; last++) {
+ if (!IndexToId(cx, last, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, last - delta, &id2))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
+ return JS_FALSE;
+ }
+ length -= delta;
+ }
+
+ /* Copy from argv into the hole to complete the splice. */
+ for (i = 0; i < argc; i++) {
+ if (!IndexToId(cx, begin + i, &id))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, obj, id, &argv[i]))
+ return JS_FALSE;
+ }
+
+ /* Update length in case we deleted elements from the end. */
+ return js_SetLengthProperty(cx, obj, length);
+}
+#endif /* JS_HAS_MORE_PERL_FUN */
+
+#if JS_HAS_SEQUENCE_OPS
+/*
+ * Python-esque sequence operations.
+ */
+static JSBool
+array_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSObject *nobj, *aobj;
+ jsuint length, alength, slot;
+ uintN i;
+ jsval v;
+ jsid id, id2;
+
+ /* Treat obj as the first argument; see ECMA 15.4.4.4. */
+ --argv;
+ JS_ASSERT(obj == JSVAL_TO_OBJECT(argv[0]));
+
+ /* Create a new Array object and store it in the rval local root. */
+ nobj = js_NewArrayObject(cx, 0, NULL);
+ if (!nobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(nobj);
+
+ /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
+ length = 0;
+ for (i = 0; i <= argc; i++) {
+ v = argv[i];
+ if (JSVAL_IS_OBJECT(v)) {
+ aobj = JSVAL_TO_OBJECT(v);
+ if (aobj && OBJ_GET_CLASS(cx, aobj) == &js_ArrayClass) {
+ if (!OBJ_GET_PROPERTY(cx, aobj,
+ (jsid)cx->runtime->atomState.lengthAtom,
+ &v)) {
+ return JS_FALSE;
+ }
+ if (!ValueIsLength(cx, v, &alength))
+ return JS_FALSE;
+ for (slot = 0; slot < alength; slot++) {
+ if (!IndexToId(cx, slot, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, length + slot, &id2))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, aobj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, nobj, id2, &v))
+ return JS_FALSE;
+ }
+ length += alength;
+ continue;
+ }
+ }
+
+ if (!IndexToId(cx, length, &id))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, nobj, id, &v))
+ return JS_FALSE;
+ length++;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSObject *nobj;
+ jsuint length, begin, end, slot;
+ jsdouble d;
+ jsid id, id2;
+ jsval v;
+
+ nobj = js_NewArrayObject(cx, 0, NULL);
+ if (!nobj)
+ return JS_FALSE;
+
+ if (!js_GetLengthProperty(cx, obj, &length))
+ return JS_FALSE;
+ begin = 0;
+ end = length;
+
+ if (argc > 0) {
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ d = js_DoubleToInteger(d);
+ if (d < 0) {
+ d += length;
+ if (d < 0)
+ d = 0;
+ } else if (d > length) {
+ d = length;
+ }
+ begin = (jsuint)d;
+
+ if (argc > 1) {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+ d = js_DoubleToInteger(d);
+ if (d < 0) {
+ d += length;
+ if (d < 0)
+ d = 0;
+ } else if (d > length) {
+ d = length;
+ }
+ end = (jsuint)d;
+ }
+ }
+
+ for (slot = begin; slot < end; slot++) {
+ if (!IndexToId(cx, slot, &id))
+ return JS_FALSE;
+ if (!IndexToId(cx, slot - begin, &id2))
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+ return JS_FALSE;
+ if (!OBJ_SET_PROPERTY(cx, nobj, id2, &v))
+ return JS_FALSE;
+ }
+ *rval = OBJECT_TO_JSVAL(nobj);
+ return JS_TRUE;
+}
+#endif /* JS_HAS_SEQUENCE_OPS */
+
+static JSFunctionSpec array_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, array_toSource, 0,0,0},
+#endif
+ {js_toString_str, array_toString, 0,0,0},
+ {js_toLocaleString_str, array_toLocaleString, 0,0,0},
+
+ /* Perl-ish methods. */
+#if JS_HAS_SOME_PERL_FUN
+ {"join", array_join, 1,0,0},
+ {"reverse", array_reverse, 0,0,0},
+ {"sort", array_sort, 1,0,0},
+#endif
+#if JS_HAS_MORE_PERL_FUN
+ {"push", array_push, 1,0,0},
+ {"pop", array_pop, 0,0,0},
+ {"shift", array_shift, 0,0,0},
+ {"unshift", array_unshift, 1,0,0},
+ {"splice", array_splice, 1,0,0},
+#endif
+
+ /* Python-esque sequence methods. */
+#if JS_HAS_SEQUENCE_OPS
+ {"concat", array_concat, 0,0,0},
+ {"slice", array_slice, 0,0,0},
+#endif
+
+ {0,0,0,0,0}
+};
+
+static JSBool
+Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsuint length;
+ jsval *vector;
+
+ /* If called without new, replace obj with a new Array object. */
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ }
+
+ if (argc == 0) {
+ length = 0;
+ vector = NULL;
+ } else if (cx->version == JSVERSION_1_2) {
+ length = (jsuint) argc;
+ vector = argv;
+ } else if (argc > 1) {
+ length = (jsuint) argc;
+ vector = argv;
+ } else if (!JSVAL_IS_NUMBER(argv[0])) {
+ length = 1;
+ vector = argv;
+ } else {
+ if (!ValueIsLength(cx, argv[0], &length))
+ return JS_FALSE;
+ vector = NULL;
+ }
+ return InitArrayObject(cx, obj, length, vector);
+}
+
+JSObject *
+js_InitArrayClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+
+ proto = JS_InitClass(cx, obj, NULL, &js_ArrayClass, Array, 1,
+ NULL, array_methods, NULL, NULL);
+
+ /* Initialize the Array prototype object so it gets a length property. */
+ if (!proto || !InitArrayObject(cx, proto, 0, NULL))
+ return NULL;
+ return proto;
+}
+
+JSObject *
+js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector)
+{
+ JSObject *obj;
+
+ obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
+ if (!obj)
+ return NULL;
+ if (!InitArrayObject(cx, obj, length, vector)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ return obj;
+}
diff --git a/src/dom/js/jsarray.h b/src/dom/js/jsarray.h
new file mode 100644
index 000000000..cbb2aedf1
--- /dev/null
+++ b/src/dom/js/jsarray.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsarray_h___
+#define jsarray_h___
+/*
+ * JS Array interface.
+ */
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+extern JSClass js_ArrayClass;
+
+extern JSObject *
+js_InitArrayClass(JSContext *cx, JSObject *obj);
+
+extern JSObject *
+js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector);
+
+extern JSBool
+js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
+
+extern JSBool
+js_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length);
+
+extern JSBool
+js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
+
+/*
+ * JS-specific heap sort function.
+ */
+typedef int (*JSComparator)(const void *a, const void *b, void *arg);
+
+extern JSBool
+js_HeapSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, void *arg);
+
+JS_END_EXTERN_C
+
+#endif /* jsarray_h___ */
diff --git a/src/dom/js/jsatom.c b/src/dom/js/jsatom.c
new file mode 100644
index 000000000..59cb4b801
--- /dev/null
+++ b/src/dom/js/jsatom.c
@@ -0,0 +1,911 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS atom table.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jshash.h" /* Added by JSIFY */
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsgc.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsopcode.h"
+#include "jsstr.h"
+
+JS_FRIEND_API(const char *)
+js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
+{
+ JSString *str;
+ const char *bytes;
+
+ str = js_QuoteString(cx, ATOM_TO_STRING(atom), 0);
+ if (!str)
+ return NULL;
+ bytes = js_GetStringBytes(str);
+ if (!bytes)
+ JS_ReportOutOfMemory(cx);
+ return bytes;
+}
+
+extern const char js_Error_str[]; /* trivial, from jsexn.h */
+
+/*
+ * Keep this in sync with jspubtd.h -- an assertion below will insist that
+ * its length match the JSType enum's JSTYPE_LIMIT limit value.
+ */
+const char *js_type_str[] = {
+ "undefined",
+ "object",
+ "function",
+ "string",
+ "number",
+ "boolean",
+};
+
+const char *js_boolean_str[] = {
+ js_false_str,
+ js_true_str
+};
+
+const char js_Arguments_str[] = "Arguments";
+const char js_Array_str[] = "Array";
+const char js_Boolean_str[] = "Boolean";
+const char js_Call_str[] = "Call";
+const char js_Date_str[] = "Date";
+const char js_Function_str[] = "Function";
+const char js_Math_str[] = "Math";
+const char js_Number_str[] = "Number";
+const char js_Object_str[] = "Object";
+const char js_RegExp_str[] = "RegExp";
+const char js_Script_str[] = "Script";
+const char js_String_str[] = "String";
+const char js_anonymous_str[] = "anonymous";
+const char js_arguments_str[] = "arguments";
+const char js_arity_str[] = "arity";
+const char js_callee_str[] = "callee";
+const char js_caller_str[] = "caller";
+const char js_class_prototype_str[] = "prototype";
+const char js_constructor_str[] = "constructor";
+const char js_count_str[] = "__count__";
+const char js_eval_str[] = "eval";
+const char js_getter_str[] = "getter";
+const char js_get_str[] = "get";
+const char js_index_str[] = "index";
+const char js_input_str[] = "input";
+const char js_length_str[] = "length";
+const char js_name_str[] = "name";
+const char js_noSuchMethod_str[] = "__noSuchMethod__";
+const char js_parent_str[] = "__parent__";
+const char js_proto_str[] = "__proto__";
+const char js_setter_str[] = "setter";
+const char js_set_str[] = "set";
+const char js_toSource_str[] = "toSource";
+const char js_toString_str[] = "toString";
+const char js_toLocaleString_str[] = "toLocaleString";
+const char js_valueOf_str[] = "valueOf";
+
+#define HASH_OBJECT(o) ((JSHashNumber)(o) >> JSVAL_TAGBITS)
+#define HASH_INT(i) ((JSHashNumber)(i))
+#define HASH_DOUBLE(dp) ((JSHashNumber)(((uint32*)(dp))[0] ^ ((uint32*)(dp))[1]))
+#define HASH_BOOLEAN(b) ((JSHashNumber)(b))
+
+JS_STATIC_DLL_CALLBACK(JSHashNumber)
+js_hash_atom_key(const void *key)
+{
+ jsval v;
+ jsdouble *dp;
+
+ /* Order JSVAL_IS_* tests by likelihood of success. */
+ v = (jsval)key;
+ if (JSVAL_IS_STRING(v))
+ return js_HashString(JSVAL_TO_STRING(v));
+ if (JSVAL_IS_INT(v))
+ return HASH_INT(JSVAL_TO_INT(v));
+ if (JSVAL_IS_DOUBLE(v)) {
+ dp = JSVAL_TO_DOUBLE(v);
+ return HASH_DOUBLE(dp);
+ }
+ if (JSVAL_IS_OBJECT(v))
+ return HASH_OBJECT(JSVAL_TO_OBJECT(v));
+ if (JSVAL_IS_BOOLEAN(v))
+ return HASH_BOOLEAN(JSVAL_TO_BOOLEAN(v));
+ return (JSHashNumber)v;
+}
+
+JS_STATIC_DLL_CALLBACK(intN)
+js_compare_atom_keys(const void *k1, const void *k2)
+{
+ jsval v1, v2;
+
+ v1 = (jsval)k1, v2 = (jsval)k2;
+ if (JSVAL_IS_STRING(v1) && JSVAL_IS_STRING(v2))
+ return !js_CompareStrings(JSVAL_TO_STRING(v1), JSVAL_TO_STRING(v2));
+ if (JSVAL_IS_DOUBLE(v1) && JSVAL_IS_DOUBLE(v2)) {
+ double d1 = *JSVAL_TO_DOUBLE(v1);
+ double d2 = *JSVAL_TO_DOUBLE(v2);
+ if (JSDOUBLE_IS_NaN(d1))
+ return JSDOUBLE_IS_NaN(d2);
+#if defined(XP_WIN)
+ /* XXX MSVC miscompiles such that (NaN == 0) */
+ if (JSDOUBLE_IS_NaN(d2))
+ return JS_FALSE;
+#endif
+ return d1 == d2;
+ }
+ return v1 == v2;
+}
+
+JS_STATIC_DLL_CALLBACK(int)
+js_compare_stub(const void *v1, const void *v2)
+{
+ return 1;
+}
+
+/* These next two are exported to jsscript.c and used similarly there. */
+void * JS_DLL_CALLBACK
+js_alloc_table_space(void *priv, size_t size)
+{
+ return malloc(size);
+}
+
+void JS_DLL_CALLBACK
+js_free_table_space(void *priv, void *item)
+{
+ free(item);
+}
+
+JS_STATIC_DLL_CALLBACK(JSHashEntry *)
+js_alloc_atom(void *priv, const void *key)
+{
+ JSAtomState *state = (JSAtomState *) priv;
+ JSAtom *atom;
+
+ atom = (JSAtom *) malloc(sizeof(JSAtom));
+ if (!atom)
+ return NULL;
+#ifdef JS_THREADSAFE
+ state->tablegen++;
+#endif
+ atom->entry.key = key;
+ atom->entry.value = NULL;
+ atom->flags = 0;
+ atom->number = state->number++;
+ return &atom->entry;
+}
+
+JS_STATIC_DLL_CALLBACK(void)
+js_free_atom(void *priv, JSHashEntry *he, uintN flag)
+{
+ if (flag != HT_FREE_ENTRY)
+ return;
+#ifdef JS_THREADSAFE
+ ((JSAtomState *)priv)->tablegen++;
+#endif
+ free(he);
+}
+
+static JSHashAllocOps atom_alloc_ops = {
+ js_alloc_table_space, js_free_table_space,
+ js_alloc_atom, js_free_atom
+};
+
+#define JS_ATOM_HASH_SIZE 1024
+
+JSBool
+js_InitAtomState(JSContext *cx, JSAtomState *state)
+{
+ state->table = JS_NewHashTable(JS_ATOM_HASH_SIZE, js_hash_atom_key,
+ js_compare_atom_keys, js_compare_stub,
+ &atom_alloc_ops, state);
+ if (!state->table) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+
+ state->runtime = cx->runtime;
+#ifdef JS_THREADSAFE
+ js_InitLock(&state->lock);
+ state->tablegen = 0;
+#endif
+
+ if (!js_InitPinnedAtoms(cx, state)) {
+ js_FreeAtomState(cx, state);
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_InitPinnedAtoms(JSContext *cx, JSAtomState *state)
+{
+ uintN i;
+
+#define FROB(lval,str) \
+ JS_BEGIN_MACRO \
+ if (!(state->lval = js_Atomize(cx, str, strlen(str), ATOM_PINNED))) \
+ return JS_FALSE; \
+ JS_END_MACRO
+
+ JS_ASSERT(sizeof js_type_str / sizeof js_type_str[0] == JSTYPE_LIMIT);
+ for (i = 0; i < JSTYPE_LIMIT; i++)
+ FROB(typeAtoms[i], js_type_str[i]);
+
+ FROB(booleanAtoms[0], js_false_str);
+ FROB(booleanAtoms[1], js_true_str);
+ FROB(nullAtom, js_null_str);
+
+ FROB(ArgumentsAtom, js_Arguments_str);
+ FROB(ArrayAtom, js_Array_str);
+ FROB(BooleanAtom, js_Boolean_str);
+ FROB(CallAtom, js_Call_str);
+ FROB(DateAtom, js_Date_str);
+ FROB(ErrorAtom, js_Error_str);
+ FROB(FunctionAtom, js_Function_str);
+ FROB(MathAtom, js_Math_str);
+ FROB(NumberAtom, js_Number_str);
+ FROB(ObjectAtom, js_Object_str);
+ FROB(RegExpAtom, js_RegExp_str);
+ FROB(ScriptAtom, js_Script_str);
+ FROB(StringAtom, js_String_str);
+ FROB(anonymousAtom, js_anonymous_str);
+ FROB(argumentsAtom, js_arguments_str);
+ FROB(arityAtom, js_arity_str);
+ FROB(calleeAtom, js_callee_str);
+ FROB(callerAtom, js_caller_str);
+ FROB(classPrototypeAtom, js_class_prototype_str);
+ FROB(constructorAtom, js_constructor_str);
+ FROB(countAtom, js_count_str);
+ FROB(evalAtom, js_eval_str);
+ FROB(getAtom, js_get_str);
+ FROB(getterAtom, js_getter_str);
+ FROB(indexAtom, js_index_str);
+ FROB(inputAtom, js_input_str);
+ FROB(lengthAtom, js_length_str);
+ FROB(nameAtom, js_name_str);
+ FROB(noSuchMethodAtom, js_noSuchMethod_str);
+ FROB(parentAtom, js_parent_str);
+ FROB(protoAtom, js_proto_str);
+ FROB(setAtom, js_set_str);
+ FROB(setterAtom, js_setter_str);
+ FROB(toSourceAtom, js_toSource_str);
+ FROB(toStringAtom, js_toString_str);
+ FROB(toLocaleStringAtom, js_toLocaleString_str);
+ FROB(valueOfAtom, js_valueOf_str);
+
+#undef FROB
+
+ memset(&state->lazy, 0, sizeof state->lazy);
+ return JS_TRUE;
+}
+
+/* NB: cx unused; js_FinishAtomState calls us with null cx. */
+void
+js_FreeAtomState(JSContext *cx, JSAtomState *state)
+{
+ if (state->table)
+ JS_HashTableDestroy(state->table);
+#ifdef JS_THREADSAFE
+ js_FinishLock(&state->lock);
+#endif
+ memset(state, 0, sizeof *state);
+}
+
+typedef struct UninternArgs {
+ JSRuntime *rt;
+ jsatomid leaks;
+} UninternArgs;
+
+JS_STATIC_DLL_CALLBACK(intN)
+js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
+{
+ JSAtom *atom;
+ UninternArgs *args;
+
+ atom = (JSAtom *)he;
+ args = (UninternArgs *)arg;
+ if (ATOM_IS_STRING(atom))
+ js_FinalizeStringRT(args->rt, ATOM_TO_STRING(atom));
+ else if (ATOM_IS_OBJECT(atom))
+ args->leaks++;
+ return HT_ENUMERATE_NEXT;
+}
+
+void
+js_FinishAtomState(JSAtomState *state)
+{
+ UninternArgs args;
+
+ if (!state->table)
+ return;
+ args.rt = state->runtime;
+ args.leaks = 0;
+ JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, &args);
+#ifdef DEBUG
+ if (args.leaks != 0) {
+ fprintf(stderr,
+"JS engine warning: %lu atoms remain after destroying the JSRuntime.\n"
+" These atoms may point to freed memory. Things reachable\n"
+" through them have not been finalized.\n",
+ (unsigned long) args.leaks);
+ }
+#endif
+ js_FreeAtomState(NULL, state);
+}
+
+typedef struct MarkArgs {
+ uintN gcflags;
+ JSGCThingMarker mark;
+ void *data;
+} MarkArgs;
+
+JS_STATIC_DLL_CALLBACK(intN)
+js_atom_marker(JSHashEntry *he, intN i, void *arg)
+{
+ JSAtom *atom;
+ MarkArgs *args;
+ jsval key;
+
+ atom = (JSAtom *)he;
+ args = (MarkArgs *)arg;
+ if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) ||
+ (args->gcflags & GC_KEEP_ATOMS)) {
+ atom->flags |= ATOM_MARK;
+ key = ATOM_KEY(atom);
+ if (JSVAL_IS_GCTHING(key))
+ args->mark(JSVAL_TO_GCTHING(key), args->data);
+ }
+ return HT_ENUMERATE_NEXT;
+}
+
+void
+js_MarkAtomState(JSAtomState *state, uintN gcflags, JSGCThingMarker mark,
+ void *data)
+{
+ MarkArgs args;
+
+ if (!state->table)
+ return;
+ args.gcflags = gcflags;
+ args.mark = mark;
+ args.data = data;
+ JS_HashTableEnumerateEntries(state->table, js_atom_marker, &args);
+}
+
+JS_STATIC_DLL_CALLBACK(intN)
+js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
+{
+ JSAtom *atom;
+ JSAtomState *state;
+
+ atom = (JSAtom *)he;
+ if (atom->flags & ATOM_MARK) {
+ atom->flags &= ~ATOM_MARK;
+ state = (JSAtomState *)arg;
+ state->liveAtoms++;
+ return HT_ENUMERATE_NEXT;
+ }
+ JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
+ atom->entry.key = NULL;
+ atom->flags = 0;
+ return HT_ENUMERATE_REMOVE;
+}
+
+void
+js_SweepAtomState(JSAtomState *state)
+{
+ state->liveAtoms = 0;
+ if (state->table)
+ JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, state);
+}
+
+JS_STATIC_DLL_CALLBACK(intN)
+js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
+{
+ JSAtom *atom;
+
+ atom = (JSAtom *)he;
+ atom->flags &= ~ATOM_PINNED;
+ return HT_ENUMERATE_NEXT;
+}
+
+void
+js_UnpinPinnedAtoms(JSAtomState *state)
+{
+ if (state->table)
+ JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
+}
+
+static JSAtom *
+js_AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash, uintN flags)
+{
+ JSAtomState *state;
+ JSHashTable *table;
+ JSHashEntry *he, **hep;
+ JSAtom *atom;
+
+ state = &cx->runtime->atomState;
+ JS_LOCK(&state->lock, cx);
+ table = state->table;
+ hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
+ if ((he = *hep) == NULL) {
+ he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
+ if (!he) {
+ JS_ReportOutOfMemory(cx);
+ atom = NULL;
+ goto out;
+ }
+ }
+
+ atom = (JSAtom *)he;
+ atom->flags |= flags;
+ cx->lastAtom = atom;
+out:
+ JS_UNLOCK(&state->lock,cx);
+ return atom;
+}
+
+JSAtom *
+js_AtomizeObject(JSContext *cx, JSObject *obj, uintN flags)
+{
+ jsval key;
+ JSHashNumber keyHash;
+
+ /* XXX must be set in the following order or MSVC1.52 will crash */
+ keyHash = HASH_OBJECT(obj);
+ key = OBJECT_TO_JSVAL(obj);
+ return js_AtomizeHashedKey(cx, key, keyHash, flags);
+}
+
+JSAtom *
+js_AtomizeBoolean(JSContext *cx, JSBool b, uintN flags)
+{
+ jsval key;
+ JSHashNumber keyHash;
+
+ key = BOOLEAN_TO_JSVAL(b);
+ keyHash = HASH_BOOLEAN(b);
+ return js_AtomizeHashedKey(cx, key, keyHash, flags);
+}
+
+JSAtom *
+js_AtomizeInt(JSContext *cx, jsint i, uintN flags)
+{
+ jsval key;
+ JSHashNumber keyHash;
+
+ key = INT_TO_JSVAL(i);
+ keyHash = HASH_INT(i);
+ return js_AtomizeHashedKey(cx, key, keyHash, flags);
+}
+
+/* Worst-case alignment grain and aligning macro for 2x-sized buffer. */
+#define ALIGNMENT(t) JS_MAX(JSVAL_ALIGN, sizeof(t))
+#define ALIGN(b,t) ((t*) &(b)[ALIGNMENT(t) - (jsuword)(b) % ALIGNMENT(t)])
+
+JSAtom *
+js_AtomizeDouble(JSContext *cx, jsdouble d, uintN flags)
+{
+ jsdouble *dp;
+ JSHashNumber keyHash;
+ jsval key;
+ JSAtomState *state;
+ JSHashTable *table;
+ JSHashEntry *he, **hep;
+ JSAtom *atom;
+ char buf[2 * ALIGNMENT(double)];
+
+ dp = ALIGN(buf, double);
+ *dp = d;
+ keyHash = HASH_DOUBLE(dp);
+ key = DOUBLE_TO_JSVAL(dp);
+ state = &cx->runtime->atomState;
+ JS_LOCK(&state->lock, cx);
+ table = state->table;
+ hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
+ if ((he = *hep) == NULL) {
+#ifdef JS_THREADSAFE
+ uint32 gen = state->tablegen;
+#endif
+ JS_UNLOCK(&state->lock,cx);
+ if (!js_NewDoubleValue(cx, d, &key))
+ return NULL;
+ JS_LOCK(&state->lock, cx);
+#ifdef JS_THREADSAFE
+ if (state->tablegen != gen) {
+ hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
+ if ((he = *hep) != NULL) {
+ atom = (JSAtom *)he;
+ goto out;
+ }
+ }
+#endif
+ he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
+ if (!he) {
+ JS_ReportOutOfMemory(cx);
+ atom = NULL;
+ goto out;
+ }
+ }
+
+ atom = (JSAtom *)he;
+ atom->flags |= flags;
+ cx->lastAtom = atom;
+out:
+ JS_UNLOCK(&state->lock,cx);
+ return atom;
+}
+
+JSAtom *
+js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
+{
+ JSHashNumber keyHash;
+ jsval key;
+ JSAtomState *state;
+ JSHashTable *table;
+ JSHashEntry *he, **hep;
+ JSAtom *atom;
+
+ keyHash = js_HashString(str);
+ key = STRING_TO_JSVAL(str);
+ state = &cx->runtime->atomState;
+ JS_LOCK(&state->lock, cx);
+ table = state->table;
+ hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
+ if ((he = *hep) == NULL) {
+#ifdef JS_THREADSAFE
+ uint32 gen = state->tablegen;
+ JS_UNLOCK(&state->lock, cx);
+#endif
+
+ if (flags & ATOM_TMPSTR) {
+ str = (flags & ATOM_NOCOPY)
+ ? js_NewString(cx, str->chars, str->length, 0)
+ : js_NewStringCopyN(cx, str->chars, str->length, 0);
+ if (!str)
+ return NULL;
+ key = STRING_TO_JSVAL(str);
+ } else {
+ if (!JS_MakeStringImmutable(cx, str))
+ return NULL;
+ }
+
+#ifdef JS_THREADSAFE
+ JS_LOCK(&state->lock, cx);
+ if (state->tablegen != gen) {
+ hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
+ if ((he = *hep) != NULL) {
+ atom = (JSAtom *)he;
+ if (flags & ATOM_NOCOPY)
+ str->chars = NULL;
+ goto out;
+ }
+ }
+#endif
+
+ he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
+ if (!he) {
+ JS_ReportOutOfMemory(cx);
+ atom = NULL;
+ goto out;
+ }
+ }
+
+ atom = (JSAtom *)he;
+ atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED);
+ cx->lastAtom = atom;
+out:
+ JS_UNLOCK(&state->lock,cx);
+ return atom;
+}
+
+JS_FRIEND_API(JSAtom *)
+js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
+{
+ jschar *chars;
+ JSString *str;
+ JSAtom *atom;
+ char buf[2 * ALIGNMENT(JSString)];
+
+ /*
+ * Avoiding the malloc in js_InflateString on shorter strings saves us
+ * over 20,000 malloc calls on mozilla browser startup. This compares to
+ * only 131 calls where the string is longer than a 31 char (net) buffer.
+ * The vast majority of atomized strings are already in the hashtable. So
+ * js_AtomizeString rarely has to copy the temp string we make.
+ */
+#define ATOMIZE_BUF_MAX 32
+ jschar inflated[ATOMIZE_BUF_MAX];
+
+ if (length < ATOMIZE_BUF_MAX) {
+ js_InflateStringToBuffer(inflated, bytes, length);
+ chars = inflated;
+ } else {
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ flags |= ATOM_NOCOPY;
+ }
+
+ str = ALIGN(buf, JSString);
+
+ str->chars = chars;
+ str->length = length;
+ atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
+ if (chars != inflated && (!atom || ATOM_TO_STRING(atom)->chars != chars))
+ JS_free(cx, chars);
+ return atom;
+}
+
+JS_FRIEND_API(JSAtom *)
+js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
+{
+ JSString *str;
+ char buf[2 * ALIGNMENT(JSString)];
+
+ str = ALIGN(buf, JSString);
+ str->chars = (jschar *)chars;
+ str->length = length;
+ return js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
+}
+
+JSAtom *
+js_AtomizeValue(JSContext *cx, jsval value, uintN flags)
+{
+ if (JSVAL_IS_STRING(value))
+ return js_AtomizeString(cx, JSVAL_TO_STRING(value), flags);
+ if (JSVAL_IS_INT(value))
+ return js_AtomizeInt(cx, JSVAL_TO_INT(value), flags);
+ if (JSVAL_IS_DOUBLE(value))
+ return js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(value), flags);
+ if (JSVAL_IS_OBJECT(value))
+ return js_AtomizeObject(cx, JSVAL_TO_OBJECT(value), flags);
+ if (JSVAL_IS_BOOLEAN(value))
+ return js_AtomizeBoolean(cx, JSVAL_TO_BOOLEAN(value), flags);
+ return js_AtomizeHashedKey(cx, value, (JSHashNumber)value, flags);
+}
+
+JSAtom *
+js_ValueToStringAtom(JSContext *cx, jsval v)
+{
+ JSString *str;
+
+ str = js_ValueToString(cx, v);
+ if (!str)
+ return NULL;
+ return js_AtomizeString(cx, str, 0);
+}
+
+JS_STATIC_DLL_CALLBACK(JSHashNumber)
+js_hash_atom_ptr(const void *key)
+{
+ const JSAtom *atom = key;
+ return atom->number;
+}
+
+JS_STATIC_DLL_CALLBACK(void *)
+js_alloc_temp_space(void *priv, size_t size)
+{
+ JSContext *cx = priv;
+ void *space;
+
+ JS_ARENA_ALLOCATE(space, &cx->tempPool, size);
+ if (!space)
+ JS_ReportOutOfMemory(cx);
+ return space;
+}
+
+JS_STATIC_DLL_CALLBACK(void)
+js_free_temp_space(void *priv, void *item)
+{
+}
+
+JS_STATIC_DLL_CALLBACK(JSHashEntry *)
+js_alloc_temp_entry(void *priv, const void *key)
+{
+ JSContext *cx = priv;
+ JSAtomListElement *ale;
+
+ JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool);
+ if (!ale) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ return &ale->entry;
+}
+
+JS_STATIC_DLL_CALLBACK(void)
+js_free_temp_entry(void *priv, JSHashEntry *he, uintN flag)
+{
+}
+
+static JSHashAllocOps temp_alloc_ops = {
+ js_alloc_temp_space, js_free_temp_space,
+ js_alloc_temp_entry, js_free_temp_entry
+};
+
+JSAtomListElement *
+js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al)
+{
+ JSAtomListElement *ale, *ale2, *next;
+ JSHashEntry **hep;
+
+ ATOM_LIST_LOOKUP(ale, hep, al, atom);
+ if (!ale) {
+ if (al->count <= 5) {
+ /* Few enough for linear search, no hash table needed. */
+ JS_ASSERT(!al->table);
+ ale = (JSAtomListElement *)js_alloc_temp_entry(cx, atom);
+ if (!ale)
+ return NULL;
+ ALE_SET_ATOM(ale, atom);
+ ALE_SET_NEXT(ale, al->list);
+ al->list = ale;
+ } else {
+ /* We want to hash. Have we already made a hash table? */
+ if (!al->table) {
+ /* No hash table yet, so hep had better be null! */
+ JS_ASSERT(!hep);
+ al->table = JS_NewHashTable(8, js_hash_atom_ptr,
+ JS_CompareValues, JS_CompareValues,
+ &temp_alloc_ops, cx);
+ if (!al->table)
+ return NULL;
+
+ /* Insert each ale on al->list into the new hash table. */
+ for (ale2 = al->list; ale2; ale2 = next) {
+ next = ALE_NEXT(ale2);
+ ale2->entry.keyHash = ALE_ATOM(ale2)->number;
+ hep = JS_HashTableRawLookup(al->table, ale2->entry.keyHash,
+ ale2->entry.key);
+ ALE_SET_NEXT(ale2, *hep);
+ *hep = &ale2->entry;
+ }
+ al->list = NULL;
+
+ /* Set hep for insertion of atom's ale, immediately below. */
+ hep = JS_HashTableRawLookup(al->table, atom->number, atom);
+ }
+
+ /* Finally, add an entry for atom into the hash bucket at hep. */
+ ale = (JSAtomListElement *)
+ JS_HashTableRawAdd(al->table, hep, atom->number, atom, NULL);
+ if (!ale)
+ return NULL;
+ }
+
+ ALE_SET_INDEX(ale, al->count++);
+ }
+ return ale;
+}
+
+JS_FRIEND_API(JSAtom *)
+js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i)
+{
+ JSAtom *atom;
+ static JSAtom dummy;
+
+ JS_ASSERT(map->vector && i < map->length);
+ if (!map->vector || i >= map->length) {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%lu", (unsigned long)i);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_ATOMIC_NUMBER, numBuf);
+ return &dummy;
+ }
+ atom = map->vector[i];
+ JS_ASSERT(atom);
+ return atom;
+}
+
+JS_STATIC_DLL_CALLBACK(intN)
+js_map_atom(JSHashEntry *he, intN i, void *arg)
+{
+ JSAtomListElement *ale = (JSAtomListElement *)he;
+ JSAtom **vector = arg;
+
+ vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
+ return HT_ENUMERATE_NEXT;
+}
+
+#ifdef DEBUG
+jsrefcount js_atom_map_count;
+jsrefcount js_atom_map_hash_table_count;
+#endif
+
+JS_FRIEND_API(JSBool)
+js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al)
+{
+ JSAtom **vector;
+ JSAtomListElement *ale;
+ uint32 count;
+
+#ifdef DEBUG
+ JS_ATOMIC_INCREMENT(&js_atom_map_count);
+#endif
+ ale = al->list;
+ if (!ale && !al->table) {
+ map->vector = NULL;
+ map->length = 0;
+ return JS_TRUE;
+ }
+
+ count = al->count;
+ if (count >= ATOM_INDEX_LIMIT) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_TOO_MANY_LITERALS);
+ return JS_FALSE;
+ }
+ vector = (JSAtom **) JS_malloc(cx, (size_t) count * sizeof *vector);
+ if (!vector)
+ return JS_FALSE;
+
+ if (al->table) {
+#ifdef DEBUG
+ JS_ATOMIC_INCREMENT(&js_atom_map_hash_table_count);
+#endif
+ JS_HashTableEnumerateEntries(al->table, js_map_atom, vector);
+ } else {
+ do {
+ vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
+ } while ((ale = ALE_NEXT(ale)) != NULL);
+ }
+ ATOM_LIST_INIT(al);
+
+ map->vector = vector;
+ map->length = (jsatomid)count;
+ return JS_TRUE;
+}
+
+JS_FRIEND_API(void)
+js_FreeAtomMap(JSContext *cx, JSAtomMap *map)
+{
+ if (map->vector) {
+ JS_free(cx, map->vector);
+ map->vector = NULL;
+ }
+ map->length = 0;
+}
diff --git a/src/dom/js/jsatom.h b/src/dom/js/jsatom.h
new file mode 100644
index 000000000..ec9b52f80
--- /dev/null
+++ b/src/dom/js/jsatom.h
@@ -0,0 +1,409 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsatom_h___
+#define jsatom_h___
+/*
+ * JS atom table.
+ */
+#include <stddef.h>
+#include "jstypes.h"
+#include "jshash.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+#ifdef JS_THREADSAFE
+#include "jslock.h"
+#endif
+
+JS_BEGIN_EXTERN_C
+
+#define ATOM_PINNED 0x01 /* atom is pinned against GC */
+#define ATOM_INTERNED 0x02 /* pinned variant for JS_Intern* API */
+#define ATOM_MARK 0x04 /* atom is reachable via GC */
+#define ATOM_NOCOPY 0x40 /* don't copy atom string bytes */
+#define ATOM_TMPSTR 0x80 /* internal, to avoid extra string */
+
+struct JSAtom {
+ JSHashEntry entry; /* key is jsval, value keyword info */
+ uint32 flags; /* pinned, interned, and mark flags */
+ jsatomid number; /* atom serial number and hash code */
+};
+
+#define ATOM_KEY(atom) ((jsval)(atom)->entry.key)
+#define ATOM_IS_OBJECT(atom) JSVAL_IS_OBJECT(ATOM_KEY(atom))
+#define ATOM_TO_OBJECT(atom) JSVAL_TO_OBJECT(ATOM_KEY(atom))
+#define ATOM_IS_INT(atom) JSVAL_IS_INT(ATOM_KEY(atom))
+#define ATOM_TO_INT(atom) JSVAL_TO_INT(ATOM_KEY(atom))
+#define ATOM_IS_DOUBLE(atom) JSVAL_IS_DOUBLE(ATOM_KEY(atom))
+#define ATOM_TO_DOUBLE(atom) JSVAL_TO_DOUBLE(ATOM_KEY(atom))
+#define ATOM_IS_STRING(atom) JSVAL_IS_STRING(ATOM_KEY(atom))
+#define ATOM_TO_STRING(atom) JSVAL_TO_STRING(ATOM_KEY(atom))
+#define ATOM_IS_BOOLEAN(atom) JSVAL_IS_BOOLEAN(ATOM_KEY(atom))
+#define ATOM_TO_BOOLEAN(atom) JSVAL_TO_BOOLEAN(ATOM_KEY(atom))
+
+/*
+ * Return a printable, lossless char[] representation of a string-type atom.
+ * The lifetime of the result extends at least until the next GC activation,
+ * longer if cx's string newborn root is not overwritten.
+ */
+extern JS_FRIEND_API(const char *)
+js_AtomToPrintableString(JSContext *cx, JSAtom *atom);
+
+#define ATOM_KEYWORD(atom) ((struct keyword *)(atom)->entry.value)
+#define ATOM_SET_KEYWORD(atom,kw) ((atom)->entry.value = (kw))
+
+struct JSAtomListElement {
+ JSHashEntry entry;
+};
+
+#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key)
+#define ALE_INDEX(ale) ((jsatomid) (ale)->entry.value)
+#define ALE_JSOP(ale) ((JSOp) (ale)->entry.value)
+#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next)
+
+#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom))
+#define ALE_SET_INDEX(ale,index)((ale)->entry.value = (void *)(index))
+#define ALE_SET_JSOP(ale,op) ((ale)->entry.value = (void *)(op))
+#define ALE_SET_NEXT(ale,link) ((ale)->entry.next = (JSHashEntry *)(link))
+
+struct JSAtomList {
+ JSAtomListElement *list; /* literals indexed for mapping */
+ JSHashTable *table; /* hash table if list gets too long */
+ jsuint count; /* count of indexed literals */
+};
+
+#define ATOM_LIST_INIT(al) ((al)->list = NULL, (al)->table = NULL, \
+ (al)->count = 0)
+
+#define ATOM_LIST_SEARCH(_ale,_al,_atom) \
+ JS_BEGIN_MACRO \
+ JSHashEntry **_hep; \
+ ATOM_LIST_LOOKUP(_ale, _hep, _al, _atom); \
+ JS_END_MACRO
+
+#define ATOM_LIST_LOOKUP(_ale,_hep,_al,_atom) \
+ JS_BEGIN_MACRO \
+ if ((_al)->table) { \
+ _hep = JS_HashTableRawLookup((_al)->table, _atom->number, _atom); \
+ _ale = *_hep ? (JSAtomListElement *) *_hep : NULL; \
+ } else { \
+ JSAtomListElement **_alep = &(_al)->list; \
+ _hep = NULL; \
+ while ((_ale = *_alep) != NULL) { \
+ if (ALE_ATOM(_ale) == (_atom)) { \
+ /* Hit, move atom's element to the front of the list. */ \
+ *_alep = ALE_NEXT(_ale); \
+ ALE_SET_NEXT(_ale, (_al)->list); \
+ (_al)->list = _ale; \
+ break; \
+ } \
+ _alep = (JSAtomListElement **)&_ale->entry.next; \
+ } \
+ } \
+ JS_END_MACRO
+
+struct JSAtomMap {
+ JSAtom **vector; /* array of ptrs to indexed atoms */
+ jsatomid length; /* count of (to-be-)indexed atoms */
+};
+
+struct JSAtomState {
+ JSRuntime *runtime; /* runtime that owns us */
+ JSHashTable *table; /* hash table containing all atoms */
+ jsatomid number; /* one beyond greatest atom number */
+ jsatomid liveAtoms; /* number of live atoms after last GC */
+
+ /* Type names and value literals. */
+ JSAtom *typeAtoms[JSTYPE_LIMIT];
+ JSAtom *booleanAtoms[2];
+ JSAtom *nullAtom;
+
+ /* Various built-in or commonly-used atoms, pinned on first context. */
+ JSAtom *ArgumentsAtom;
+ JSAtom *ArrayAtom;
+ JSAtom *BooleanAtom;
+ JSAtom *CallAtom;
+ JSAtom *DateAtom;
+ JSAtom *ErrorAtom;
+ JSAtom *FunctionAtom;
+ JSAtom *MathAtom;
+ JSAtom *NumberAtom;
+ JSAtom *ObjectAtom;
+ JSAtom *RegExpAtom;
+ JSAtom *ScriptAtom;
+ JSAtom *StringAtom;
+ JSAtom *anonymousAtom;
+ JSAtom *argumentsAtom;
+ JSAtom *arityAtom;
+ JSAtom *calleeAtom;
+ JSAtom *callerAtom;
+ JSAtom *classPrototypeAtom;
+ JSAtom *constructorAtom;
+ JSAtom *countAtom;
+ JSAtom *evalAtom;
+ JSAtom *getAtom;
+ JSAtom *getterAtom;
+ JSAtom *indexAtom;
+ JSAtom *inputAtom;
+ JSAtom *lengthAtom;
+ JSAtom *nameAtom;
+ JSAtom *noSuchMethodAtom;
+ JSAtom *parentAtom;
+ JSAtom *protoAtom;
+ JSAtom *setAtom;
+ JSAtom *setterAtom;
+ JSAtom *toLocaleStringAtom;
+ JSAtom *toSourceAtom;
+ JSAtom *toStringAtom;
+ JSAtom *valueOfAtom;
+
+ /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
+ struct {
+ JSAtom *EvalErrorAtom;
+ JSAtom *InfinityAtom;
+ JSAtom *InternalErrorAtom;
+ JSAtom *NaNAtom;
+ JSAtom *RangeErrorAtom;
+ JSAtom *ReferenceErrorAtom;
+ JSAtom *SyntaxErrorAtom;
+ JSAtom *TypeErrorAtom;
+ JSAtom *URIErrorAtom;
+ JSAtom *decodeURIAtom;
+ JSAtom *decodeURIComponentAtom;
+ JSAtom *defineGetterAtom;
+ JSAtom *defineSetterAtom;
+ JSAtom *encodeURIAtom;
+ JSAtom *encodeURIComponentAtom;
+ JSAtom *escapeAtom;
+ JSAtom *hasOwnPropertyAtom;
+ JSAtom *isFiniteAtom;
+ JSAtom *isNaNAtom;
+ JSAtom *isPrototypeOfAtom;
+ JSAtom *lookupGetterAtom;
+ JSAtom *lookupSetterAtom;
+ JSAtom *parseFloatAtom;
+ JSAtom *parseIntAtom;
+ JSAtom *propertyIsEnumerableAtom;
+ JSAtom *unescapeAtom;
+ JSAtom *unevalAtom;
+ JSAtom *unwatchAtom;
+ JSAtom *watchAtom;
+ } lazy;
+
+#ifdef JS_THREADSAFE
+ JSThinLock lock;
+ volatile uint32 tablegen;
+#endif
+};
+
+/* Well-known predefined strings and their atoms. */
+extern const char *js_type_str[];
+extern const char *js_boolean_str[];
+
+extern const char js_Arguments_str[];
+extern const char js_Array_str[];
+extern const char js_Boolean_str[];
+extern const char js_Call_str[];
+extern const char js_Date_str[];
+extern const char js_Function_str[];
+extern const char js_Math_str[];
+extern const char js_Number_str[];
+extern const char js_Object_str[];
+extern const char js_RegExp_str[];
+extern const char js_Script_str[];
+extern const char js_String_str[];
+extern const char js_anonymous_str[];
+extern const char js_arguments_str[];
+extern const char js_arity_str[];
+extern const char js_callee_str[];
+extern const char js_caller_str[];
+extern const char js_class_prototype_str[];
+extern const char js_constructor_str[];
+extern const char js_count_str[];
+extern const char js_eval_str[];
+extern const char js_getter_str[];
+extern const char js_get_str[];
+extern const char js_index_str[];
+extern const char js_input_str[];
+extern const char js_length_str[];
+extern const char js_name_str[];
+extern const char js_noSuchMethod_str[];
+extern const char js_parent_str[];
+extern const char js_proto_str[];
+extern const char js_setter_str[];
+extern const char js_set_str[];
+extern const char js_toSource_str[];
+extern const char js_toString_str[];
+extern const char js_toLocaleString_str[];
+extern const char js_valueOf_str[];
+
+/*
+ * Initialize atom state. Return true on success, false with an out of
+ * memory error report on failure.
+ */
+extern JSBool
+js_InitAtomState(JSContext *cx, JSAtomState *state);
+
+/*
+ * Free and clear atom state (except for any interned string atoms).
+ */
+extern void
+js_FreeAtomState(JSContext *cx, JSAtomState *state);
+
+/*
+ * Interned strings are atoms that live until state's runtime is destroyed.
+ * This function frees all interned string atoms, and then frees and clears
+ * state's members (just as js_FreeAtomState does), unless there aren't any
+ * interned strings in state -- in which case state must be "free" already.
+ *
+ * NB: js_FreeAtomState is called for each "last" context being destroyed in
+ * a runtime, where there may yet be another context created in the runtime;
+ * whereas js_FinishAtomState is called from JS_DestroyRuntime, when we know
+ * that no more contexts will be created. Thus we minimize garbage during
+ * context-free episodes on a runtime, while preserving atoms created by the
+ * JS_Intern*String APIs for the life of the runtime.
+ */
+extern void
+js_FinishAtomState(JSAtomState *state);
+
+/*
+ * Atom garbage collection hooks.
+ */
+typedef void
+(*JSGCThingMarker)(void *thing, void *data);
+
+extern void
+js_MarkAtomState(JSAtomState *state, uintN gcflags, JSGCThingMarker mark,
+ void *data);
+
+extern void
+js_SweepAtomState(JSAtomState *state);
+
+extern JSBool
+js_InitPinnedAtoms(JSContext *cx, JSAtomState *state);
+
+extern void
+js_UnpinPinnedAtoms(JSAtomState *state);
+
+/*
+ * Find or create the atom for an object. If we create a new atom, give it the
+ * type indicated in flags. Return 0 on failure to allocate memory.
+ */
+extern JSAtom *
+js_AtomizeObject(JSContext *cx, JSObject *obj, uintN flags);
+
+/*
+ * Find or create the atom for a Boolean value. If we create a new atom, give
+ * it the type indicated in flags. Return 0 on failure to allocate memory.
+ */
+extern JSAtom *
+js_AtomizeBoolean(JSContext *cx, JSBool b, uintN flags);
+
+/*
+ * Find or create the atom for an integer value. If we create a new atom, give
+ * it the type indicated in flags. Return 0 on failure to allocate memory.
+ */
+extern JSAtom *
+js_AtomizeInt(JSContext *cx, jsint i, uintN flags);
+
+/*
+ * Find or create the atom for a double value. If we create a new atom, give
+ * it the type indicated in flags. Return 0 on failure to allocate memory.
+ */
+extern JSAtom *
+js_AtomizeDouble(JSContext *cx, jsdouble d, uintN flags);
+
+/*
+ * Find or create the atom for a string. If we create a new atom, give it the
+ * type indicated in flags. Return 0 on failure to allocate memory.
+ */
+extern JSAtom *
+js_AtomizeString(JSContext *cx, JSString *str, uintN flags);
+
+extern JS_FRIEND_API(JSAtom *)
+js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags);
+
+extern JS_FRIEND_API(JSAtom *)
+js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags);
+
+/*
+ * This variant handles all value tag types.
+ */
+extern JSAtom *
+js_AtomizeValue(JSContext *cx, jsval value, uintN flags);
+
+/*
+ * Convert v to an atomized string.
+ */
+extern JSAtom *
+js_ValueToStringAtom(JSContext *cx, jsval v);
+
+/*
+ * Assign atom an index and insert it on al.
+ */
+extern JSAtomListElement *
+js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al);
+
+/*
+ * Get the atom with index i from map.
+ */
+extern JS_FRIEND_API(JSAtom *)
+js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i);
+
+/*
+ * For all unmapped atoms recorded in al, add a mapping from the atom's index
+ * to its address. The GC must not run until all indexed atoms in atomLists
+ * have been mapped by scripts connected to live objects (Function and Script
+ * class objects have scripts as/in their private data -- the GC knows about
+ * these two classes).
+ */
+extern JS_FRIEND_API(JSBool)
+js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al);
+
+/*
+ * Free map->vector and clear map.
+ */
+extern JS_FRIEND_API(void)
+js_FreeAtomMap(JSContext *cx, JSAtomMap *map);
+
+JS_END_EXTERN_C
+
+#endif /* jsatom_h___ */
diff --git a/src/dom/js/jsautocfg.h b/src/dom/js/jsautocfg.h
new file mode 100644
index 000000000..a7f5d6bc8
--- /dev/null
+++ b/src/dom/js/jsautocfg.h
@@ -0,0 +1,50 @@
+#ifndef js_cpucfg___
+#define js_cpucfg___
+
+/* AUTOMATICALLY GENERATED - DO NOT EDIT */
+
+#define IS_LITTLE_ENDIAN 1
+#undef IS_BIG_ENDIAN
+
+#define JS_BYTES_PER_BYTE 1L
+#define JS_BYTES_PER_SHORT 2L
+#define JS_BYTES_PER_INT 4L
+#define JS_BYTES_PER_INT64 8L
+#define JS_BYTES_PER_LONG 4L
+#define JS_BYTES_PER_FLOAT 4L
+#define JS_BYTES_PER_DOUBLE 8L
+#define JS_BYTES_PER_WORD 4L
+#define JS_BYTES_PER_DWORD 8L
+
+#define JS_BITS_PER_BYTE 8L
+#define JS_BITS_PER_SHORT 16L
+#define JS_BITS_PER_INT 32L
+#define JS_BITS_PER_INT64 64L
+#define JS_BITS_PER_LONG 32L
+#define JS_BITS_PER_FLOAT 32L
+#define JS_BITS_PER_DOUBLE 64L
+#define JS_BITS_PER_WORD 32L
+
+#define JS_BITS_PER_BYTE_LOG2 3L
+#define JS_BITS_PER_SHORT_LOG2 4L
+#define JS_BITS_PER_INT_LOG2 5L
+#define JS_BITS_PER_INT64_LOG2 6L
+#define JS_BITS_PER_LONG_LOG2 5L
+#define JS_BITS_PER_FLOAT_LOG2 5L
+#define JS_BITS_PER_DOUBLE_LOG2 6L
+#define JS_BITS_PER_WORD_LOG2 5L
+
+#define JS_ALIGN_OF_SHORT 2L
+#define JS_ALIGN_OF_INT 4L
+#define JS_ALIGN_OF_LONG 4L
+#define JS_ALIGN_OF_INT64 4L
+#define JS_ALIGN_OF_FLOAT 4L
+#define JS_ALIGN_OF_DOUBLE 4L
+#define JS_ALIGN_OF_POINTER 4L
+#define JS_ALIGN_OF_WORD 4L
+
+#define JS_BYTES_PER_WORD_LOG2 2L
+#define JS_BYTES_PER_DWORD_LOG2 3L
+#define JS_WORDS_PER_DWORD_LOG2 1L
+
+#endif /* js_cpucfg___ */
diff --git a/src/dom/js/jsbit.h b/src/dom/js/jsbit.h
new file mode 100644
index 000000000..db41acf9f
--- /dev/null
+++ b/src/dom/js/jsbit.h
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsbit_h___
+#define jsbit_h___
+
+#include "jstypes.h"
+JS_BEGIN_EXTERN_C
+
+/*
+** A jsbitmap_t is a long integer that can be used for bitmaps
+*/
+typedef JSUword jsbitmap_t; /* NSPR name, a la Unix system types */
+typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */
+
+#define JS_TEST_BIT(_map,_bit) \
+ ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & (1L << ((_bit) & (JS_BITS_PER_WORD-1))))
+#define JS_SET_BIT(_map,_bit) \
+ ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= (1L << ((_bit) & (JS_BITS_PER_WORD-1))))
+#define JS_CLEAR_BIT(_map,_bit) \
+ ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= ~(1L << ((_bit) & (JS_BITS_PER_WORD-1))))
+
+/*
+** Compute the log of the least power of 2 greater than or equal to n
+*/
+extern JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 i);
+
+/*
+** Compute the log of the greatest power of 2 less than or equal to n
+*/
+extern JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 i);
+
+/*
+** Macro version of JS_CeilingLog2: Compute the log of the least power of
+** 2 greater than or equal to _n. The result is returned in _log2.
+*/
+#define JS_CEILING_LOG2(_log2,_n) \
+ JS_BEGIN_MACRO \
+ JSUint32 j_ = (JSUint32)(_n); \
+ (_log2) = 0; \
+ if ((j_) & ((j_)-1)) \
+ (_log2) += 1; \
+ if ((j_) >> 16) \
+ (_log2) += 16, (j_) >>= 16; \
+ if ((j_) >> 8) \
+ (_log2) += 8, (j_) >>= 8; \
+ if ((j_) >> 4) \
+ (_log2) += 4, (j_) >>= 4; \
+ if ((j_) >> 2) \
+ (_log2) += 2, (j_) >>= 2; \
+ if ((j_) >> 1) \
+ (_log2) += 1; \
+ JS_END_MACRO
+
+/*
+** Macro version of JS_FloorLog2: Compute the log of the greatest power of
+** 2 less than or equal to _n. The result is returned in _log2.
+**
+** This is equivalent to finding the highest set bit in the word.
+*/
+#define JS_FLOOR_LOG2(_log2,_n) \
+ JS_BEGIN_MACRO \
+ JSUint32 j_ = (JSUint32)(_n); \
+ (_log2) = 0; \
+ if ((j_) >> 16) \
+ (_log2) += 16, (j_) >>= 16; \
+ if ((j_) >> 8) \
+ (_log2) += 8, (j_) >>= 8; \
+ if ((j_) >> 4) \
+ (_log2) += 4, (j_) >>= 4; \
+ if ((j_) >> 2) \
+ (_log2) += 2, (j_) >>= 2; \
+ if ((j_) >> 1) \
+ (_log2) += 1; \
+ JS_END_MACRO
+
+JS_END_EXTERN_C
+#endif /* jsbit_h___ */
diff --git a/src/dom/js/jsbool.c b/src/dom/js/jsbool.c
new file mode 100644
index 000000000..05f596556
--- /dev/null
+++ b/src/dom/js/jsbool.c
@@ -0,0 +1,244 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS boolean implementation.
+ */
+#include "jsstddef.h"
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsstr.h"
+
+static JSClass boolean_class = {
+ "Boolean",
+ JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+#if JS_HAS_TOSOURCE
+#include "jsprf.h"
+
+static JSBool
+bool_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval v;
+ char buf[32];
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &boolean_class, argv))
+ return JS_FALSE;
+ v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ if (!JSVAL_IS_BOOLEAN(v))
+ return js_obj_toSource(cx, obj, argc, argv, rval);
+ JS_snprintf(buf, sizeof buf, "(new %s(%s))",
+ boolean_class.name,
+ js_boolean_str[JSVAL_TO_BOOLEAN(v) ? 1 : 0]);
+ str = JS_NewStringCopyZ(cx, buf);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif
+
+static JSBool
+bool_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval v;
+ JSAtom *atom;
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &boolean_class, argv))
+ return JS_FALSE;
+ v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ if (!JSVAL_IS_BOOLEAN(v))
+ return js_obj_toString(cx, obj, argc, argv, rval);
+ atom = cx->runtime->atomState.booleanAtoms[JSVAL_TO_BOOLEAN(v) ? 1 : 0];
+ str = ATOM_TO_STRING(atom);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+bool_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (!JS_InstanceOf(cx, obj, &boolean_class, argv))
+ return JS_FALSE;
+ *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ return JS_TRUE;
+}
+
+static JSFunctionSpec boolean_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, bool_toSource, 0,0,0},
+#endif
+ {js_toString_str, bool_toString, 0,0,0},
+ {js_valueOf_str, bool_valueOf, 0,0,0},
+ {0,0,0,0,0}
+};
+
+#ifdef XP_MAC
+#undef Boolean
+#define Boolean js_Boolean
+#endif
+
+static JSBool
+Boolean(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSBool b;
+ jsval bval;
+
+ if (argc != 0) {
+ if (!js_ValueToBoolean(cx, argv[0], &b))
+ return JS_FALSE;
+ bval = BOOLEAN_TO_JSVAL(b);
+ } else {
+ bval = JSVAL_FALSE;
+ }
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ *rval = bval;
+ return JS_TRUE;
+ }
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, bval);
+ return JS_TRUE;
+}
+
+JSObject *
+js_InitBooleanClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+
+ proto = JS_InitClass(cx, obj, NULL, &boolean_class, Boolean, 1,
+ NULL, boolean_methods, NULL, NULL);
+ if (!proto)
+ return NULL;
+ OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE, JSVAL_FALSE);
+ return proto;
+}
+
+JSObject *
+js_BooleanToObject(JSContext *cx, JSBool b)
+{
+ JSObject *obj;
+
+ obj = js_NewObject(cx, &boolean_class, NULL, NULL);
+ if (!obj)
+ return NULL;
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, BOOLEAN_TO_JSVAL(b));
+ return obj;
+}
+
+JSString *
+js_BooleanToString(JSContext *cx, JSBool b)
+{
+ return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]);
+}
+
+JSBool
+js_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
+{
+ JSBool b;
+ jsdouble d;
+
+#if defined _MSC_VER && _MSC_VER <= 800
+ /* MSVC1.5 coredumps */
+ if (!bp)
+ return JS_TRUE;
+ /* This should be an if-else chain, but MSVC1.5 crashes if it is. */
+#define ELSE
+#else
+#define ELSE else
+#endif
+
+ if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) {
+ /* Must return early to avoid falling thru to JSVAL_IS_OBJECT case. */
+ *bp = JS_FALSE;
+ return JS_TRUE;
+ }
+ if (JSVAL_IS_OBJECT(v)) {
+ if (!JSVERSION_IS_ECMA(cx->version)) {
+ if (!OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), JSTYPE_BOOLEAN, &v))
+ return JS_FALSE;
+ if (!JSVAL_IS_BOOLEAN(v))
+ v = JSVAL_TRUE; /* non-null object is true */
+ b = JSVAL_TO_BOOLEAN(v);
+ } else {
+ b = JS_TRUE;
+ }
+ } ELSE
+ if (JSVAL_IS_STRING(v)) {
+ b = JSSTRING_LENGTH(JSVAL_TO_STRING(v)) ? JS_TRUE : JS_FALSE;
+ } ELSE
+ if (JSVAL_IS_INT(v)) {
+ b = JSVAL_TO_INT(v) ? JS_TRUE : JS_FALSE;
+ } ELSE
+ if (JSVAL_IS_DOUBLE(v)) {
+ d = *JSVAL_TO_DOUBLE(v);
+ b = (!JSDOUBLE_IS_NaN(d) && d != 0) ? JS_TRUE : JS_FALSE;
+ } ELSE
+#if defined _MSC_VER && _MSC_VER <= 800
+ if (JSVAL_IS_BOOLEAN(v)) {
+ b = JSVAL_TO_BOOLEAN(v);
+ }
+#else
+ {
+ JS_ASSERT(JSVAL_IS_BOOLEAN(v));
+ b = JSVAL_TO_BOOLEAN(v);
+ }
+#endif
+
+#undef ELSE
+ *bp = b;
+ return JS_TRUE;
+}
diff --git a/src/dom/js/jsbool.h b/src/dom/js/jsbool.h
new file mode 100644
index 000000000..c07910f59
--- /dev/null
+++ b/src/dom/js/jsbool.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsbool_h___
+#define jsbool_h___
+/*
+ * JS boolean interface.
+ */
+
+JS_BEGIN_EXTERN_C
+
+extern JSObject *
+js_InitBooleanClass(JSContext *cx, JSObject *obj);
+
+extern JSObject *
+js_BooleanToObject(JSContext *cx, JSBool b);
+
+extern JSString *
+js_BooleanToString(JSContext *cx, JSBool b);
+
+extern JSBool
+js_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp);
+
+JS_END_EXTERN_C
+
+#endif /* jsbool_h___ */
diff --git a/src/dom/js/jsclist.h b/src/dom/js/jsclist.h
new file mode 100644
index 000000000..2eafe8e40
--- /dev/null
+++ b/src/dom/js/jsclist.h
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsclist_h___
+#define jsclist_h___
+
+#include "jstypes.h"
+
+/*
+** Circular linked list
+*/
+typedef struct JSCListStr {
+ struct JSCListStr *next;
+ struct JSCListStr *prev;
+} JSCList;
+
+/*
+** Insert element "_e" into the list, before "_l".
+*/
+#define JS_INSERT_BEFORE(_e,_l) \
+ JS_BEGIN_MACRO \
+ (_e)->next = (_l); \
+ (_e)->prev = (_l)->prev; \
+ (_l)->prev->next = (_e); \
+ (_l)->prev = (_e); \
+ JS_END_MACRO
+
+/*
+** Insert element "_e" into the list, after "_l".
+*/
+#define JS_INSERT_AFTER(_e,_l) \
+ JS_BEGIN_MACRO \
+ (_e)->next = (_l)->next; \
+ (_e)->prev = (_l); \
+ (_l)->next->prev = (_e); \
+ (_l)->next = (_e); \
+ JS_END_MACRO
+
+/*
+** Return the element following element "_e"
+*/
+#define JS_NEXT_LINK(_e) \
+ ((_e)->next)
+/*
+** Return the element preceding element "_e"
+*/
+#define JS_PREV_LINK(_e) \
+ ((_e)->prev)
+
+/*
+** Append an element "_e" to the end of the list "_l"
+*/
+#define JS_APPEND_LINK(_e,_l) JS_INSERT_BEFORE(_e,_l)
+
+/*
+** Insert an element "_e" at the head of the list "_l"
+*/
+#define JS_INSERT_LINK(_e,_l) JS_INSERT_AFTER(_e,_l)
+
+/* Return the head/tail of the list */
+#define JS_LIST_HEAD(_l) (_l)->next
+#define JS_LIST_TAIL(_l) (_l)->prev
+
+/*
+** Remove the element "_e" from it's circular list.
+*/
+#define JS_REMOVE_LINK(_e) \
+ JS_BEGIN_MACRO \
+ (_e)->prev->next = (_e)->next; \
+ (_e)->next->prev = (_e)->prev; \
+ JS_END_MACRO
+
+/*
+** Remove the element "_e" from it's circular list. Also initializes the
+** linkage.
+*/
+#define JS_REMOVE_AND_INIT_LINK(_e) \
+ JS_BEGIN_MACRO \
+ (_e)->prev->next = (_e)->next; \
+ (_e)->next->prev = (_e)->prev; \
+ (_e)->next = (_e); \
+ (_e)->prev = (_e); \
+ JS_END_MACRO
+
+/*
+** Return non-zero if the given circular list "_l" is empty, zero if the
+** circular list is not empty
+*/
+#define JS_CLIST_IS_EMPTY(_l) \
+ ((_l)->next == (_l))
+
+/*
+** Initialize a circular list
+*/
+#define JS_INIT_CLIST(_l) \
+ JS_BEGIN_MACRO \
+ (_l)->next = (_l); \
+ (_l)->prev = (_l); \
+ JS_END_MACRO
+
+#define JS_INIT_STATIC_CLIST(_l) \
+ {(_l), (_l)}
+
+#endif /* jsclist_h___ */
diff --git a/src/dom/js/jscntxt.c b/src/dom/js/jscntxt.c
new file mode 100644
index 000000000..85496b89b
--- /dev/null
+++ b/src/dom/js/jscntxt.c
@@ -0,0 +1,702 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS execution context.
+ */
+#include "jsstddef.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsclist.h"
+#include "jsprf.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdbgapi.h"
+#include "jsexn.h"
+#include "jsgc.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsscan.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+JSContext *
+js_NewContext(JSRuntime *rt, size_t stackChunkSize)
+{
+ JSContext *cx;
+ JSBool ok, first;
+
+ cx = (JSContext *) malloc(sizeof *cx);
+ if (!cx)
+ return NULL;
+ memset(cx, 0, sizeof *cx);
+
+ cx->runtime = rt;
+#if JS_STACK_GROWTH_DIRECTION > 0
+ cx->stackLimit = (jsuword)-1;
+#endif
+#ifdef JS_THREADSAFE
+ js_InitContextForLocking(cx);
+#endif
+
+ JS_LOCK_GC(rt);
+ for (;;) {
+ first = (rt->contextList.next == &rt->contextList);
+ if (rt->state == JSRTS_UP) {
+ JS_ASSERT(!first);
+ break;
+ }
+ if (rt->state == JSRTS_DOWN) {
+ JS_ASSERT(first);
+ rt->state = JSRTS_LAUNCHING;
+ break;
+ }
+ JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
+ }
+ JS_APPEND_LINK(&cx->links, &rt->contextList);
+ JS_UNLOCK_GC(rt);
+
+ /*
+ * First we do the infallible, every-time per-context initializations.
+ * Should a later, fallible initialization (js_InitRegExpStatics, e.g.,
+ * or the stuff under 'if (first)' below) fail, at least the version
+ * and arena-pools will be valid and safe to use (say, from the last GC
+ * done by js_DestroyContext).
+ */
+ cx->version = JSVERSION_DEFAULT;
+ cx->jsop_eq = JSOP_EQ;
+ cx->jsop_ne = JSOP_NE;
+ JS_InitArenaPool(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval));
+ JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble));
+
+#if JS_HAS_REGEXPS
+ if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) {
+ js_DestroyContext(cx, JS_NO_GC);
+ return NULL;
+ }
+#endif
+#if JS_HAS_EXCEPTIONS
+ cx->throwing = JS_FALSE;
+#endif
+
+ /*
+ * If cx is the first context on this runtime, initialize well-known atoms,
+ * keywords, numbers, and strings. If one of these steps should fail, the
+ * runtime will be left in a partially initialized state, with zeroes and
+ * nulls stored in the default-initialized remainder of the struct. We'll
+ * clean the runtime up under js_DestroyContext, because cx will be "last"
+ * as well as "first".
+ */
+ if (first) {
+ ok = (rt->atomState.liveAtoms == 0)
+ ? js_InitAtomState(cx, &rt->atomState)
+ : js_InitPinnedAtoms(cx, &rt->atomState);
+ if (ok)
+ ok = js_InitScanner(cx);
+ if (ok)
+ ok = js_InitRuntimeNumberState(cx);
+ if (ok)
+ ok = js_InitRuntimeStringState(cx);
+ if (!ok) {
+ js_DestroyContext(cx, JS_NO_GC);
+ return NULL;
+ }
+
+ JS_LOCK_GC(rt);
+ rt->state = JSRTS_UP;
+ JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
+ JS_UNLOCK_GC(rt);
+ }
+
+ return cx;
+}
+
+void
+js_DestroyContext(JSContext *cx, JSGCMode gcmode)
+{
+ JSRuntime *rt;
+ JSBool last;
+ JSArgumentFormatMap *map;
+
+ rt = cx->runtime;
+
+ /* Remove cx from context list first. */
+ JS_LOCK_GC(rt);
+ JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
+ JS_REMOVE_LINK(&cx->links);
+ last = (rt->contextList.next == &rt->contextList);
+ if (last)
+ rt->state = JSRTS_LANDING;
+ JS_UNLOCK_GC(rt);
+
+ if (last) {
+#ifdef JS_THREADSAFE
+ /*
+ * If cx is not in a request already, begin one now so that we wait
+ * for any racing GC started on a not-last context to finish, before
+ * we plow ahead and unpin atoms. Note that even though we begin a
+ * request here if necessary, we end all requests on cx below before
+ * forcing a final GC. This lets any not-last context destruction
+ * racing in another thread try to force or maybe run the GC, but by
+ * that point, rt->state will not be JSRTS_UP, and that GC attempt
+ * will return early.
+ */
+ if (cx->requestDepth == 0)
+ JS_BeginRequest(cx);
+#endif
+
+ /* Unpin all pinned atoms before final GC. */
+ js_UnpinPinnedAtoms(&rt->atomState);
+
+ /* Unlock and clear GC things held by runtime pointers. */
+ js_FinishRuntimeNumberState(cx);
+ js_FinishRuntimeStringState(cx);
+
+ /* Clear debugging state to remove GC roots. */
+ JS_ClearAllTraps(cx);
+ JS_ClearAllWatchPoints(cx);
+ }
+
+#if JS_HAS_REGEXPS
+ /*
+ * Remove more GC roots in regExpStatics, then collect garbage.
+ * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within
+ * XXX this function call to wait for any racing GC to complete, in the
+ * XXX case where JS_DestroyContext is called outside of a request on cx
+ */
+ js_FreeRegExpStatics(cx, &cx->regExpStatics);
+#endif
+
+#ifdef JS_THREADSAFE
+ /*
+ * Destroying a context implicitly calls JS_EndRequest(). Also, we must
+ * end our request here in case we are "last" -- in that event, another
+ * js_DestroyContext that was not last might be waiting in the GC for our
+ * request to end. We'll let it run below, just before we do the truly
+ * final GC and then free atom state.
+ *
+ * At this point, cx must be inaccessible to other threads. It's off the
+ * rt->contextList, and it should not be reachable via any object private
+ * data structure.
+ */
+ while (cx->requestDepth != 0)
+ JS_EndRequest(cx);
+#endif
+
+ if (last) {
+ /* Always force, so we wait for any racing GC to finish. */
+ js_ForceGC(cx, GC_LAST_CONTEXT);
+
+ /* Iterate until no finalizer removes a GC root or lock. */
+ while (rt->gcPoke)
+ js_GC(cx, GC_LAST_CONTEXT);
+
+ /* Try to free atom state, now that no unrooted scripts survive. */
+ if (rt->atomState.liveAtoms == 0)
+ js_FreeAtomState(cx, &rt->atomState);
+
+ /* Take the runtime down, now that it has no contexts or atoms. */
+ JS_LOCK_GC(rt);
+ rt->state = JSRTS_DOWN;
+ JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
+ JS_UNLOCK_GC(rt);
+ } else {
+ if (gcmode == JS_FORCE_GC)
+ js_ForceGC(cx, 0);
+ else if (gcmode == JS_MAYBE_GC)
+ JS_MaybeGC(cx);
+ }
+
+ /* Free the stuff hanging off of cx. */
+ JS_FinishArenaPool(&cx->stackPool);
+ JS_FinishArenaPool(&cx->tempPool);
+ if (cx->lastMessage)
+ free(cx->lastMessage);
+
+ /* Remove any argument formatters. */
+ map = cx->argumentFormatMap;
+ while (map) {
+ JSArgumentFormatMap *temp = map;
+ map = map->next;
+ JS_free(cx, temp);
+ }
+
+ /* Destroy the resolve recursion damper. */
+ if (cx->resolvingTable) {
+ JS_DHashTableDestroy(cx->resolvingTable);
+ cx->resolvingTable = NULL;
+ }
+
+ /* Finally, free cx itself. */
+ free(cx);
+}
+
+JSBool
+js_ValidContextPointer(JSRuntime *rt, JSContext *cx)
+{
+ JSCList *cl;
+
+ for (cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) {
+ if (cl == &cx->links)
+ return JS_TRUE;
+ }
+ JS_RUNTIME_METER(rt, deadContexts);
+ return JS_FALSE;
+}
+
+JSContext *
+js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
+{
+ JSContext *cx = *iterp;
+
+ if (unlocked)
+ JS_LOCK_GC(rt);
+ if (!cx)
+ cx = (JSContext *)&rt->contextList;
+ cx = (JSContext *)cx->links.next;
+ if (&cx->links == &rt->contextList)
+ cx = NULL;
+ *iterp = cx;
+ if (unlocked)
+ JS_UNLOCK_GC(rt);
+ return cx;
+}
+
+static void
+ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
+{
+ /*
+ * Check the error report, and set a JavaScript-catchable exception
+ * if the error is defined to have an associated exception. If an
+ * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
+ * on the error report, and exception-aware hosts should ignore it.
+ */
+ if (reportp && reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
+ reportp->flags |= JSREPORT_EXCEPTION;
+
+#if JS_HAS_ERROR_EXCEPTIONS
+ /*
+ * Call the error reporter only if an exception wasn't raised.
+ *
+ * If an exception was raised, then we call the debugErrorHook
+ * (if present) to give it a chance to see the error before it
+ * propagates out of scope. This is needed for compatability
+ * with the old scheme.
+ */
+ if (!js_ErrorToException(cx, message, reportp)) {
+ js_ReportErrorAgain(cx, message, reportp);
+ } else if (cx->runtime->debugErrorHook && cx->errorReporter) {
+ JSDebugErrorHook hook = cx->runtime->debugErrorHook;
+ /* test local in case debugErrorHook changed on another thread */
+ if (hook)
+ hook(cx, message, reportp, cx->runtime->debugErrorHookData);
+ }
+#else
+ js_ReportErrorAgain(cx, message, reportp);
+#endif
+}
+
+/*
+ * We don't post an exception in this case, since doing so runs into
+ * complications of pre-allocating an exception object which required
+ * running the Exception class initializer early etc.
+ * Instead we just invoke the errorReporter with an "Out Of Memory"
+ * type message, and then hope the process ends swiftly.
+ */
+void
+js_ReportOutOfMemory(JSContext *cx, JSErrorCallback callback)
+{
+ JSStackFrame *fp;
+ JSErrorReport report;
+ JSErrorReporter onError = cx->errorReporter;
+
+ /* Get the message for this error, but we won't expand any arguments. */
+ const JSErrorFormatString *efs = callback(NULL, NULL, JSMSG_OUT_OF_MEMORY);
+ const char *msg = efs ? efs->format : "Out of memory";
+
+ /* Fill out the report, but don't do anything that requires allocation. */
+ memset(&report, 0, sizeof (struct JSErrorReport));
+ report.flags = JSREPORT_ERROR;
+ report.errorNumber = JSMSG_OUT_OF_MEMORY;
+
+ /*
+ * Walk stack until we find a frame that is associated with some script
+ * rather than a native frame.
+ */
+ for (fp = cx->fp; fp; fp = fp->down) {
+ if (fp->script && fp->pc) {
+ report.filename = fp->script->filename;
+ report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+ break;
+ }
+ }
+
+ /*
+ * If debugErrorHook is present then we give it a chance to veto
+ * sending the error on to the regular ErrorReporter.
+ */
+ if (onError) {
+ JSDebugErrorHook hook = cx->runtime->debugErrorHook;
+ if (hook &&
+ !hook(cx, msg, &report, cx->runtime->debugErrorHookData)) {
+ onError = NULL;
+ }
+ }
+
+ if (onError)
+ onError(cx, msg, &report);
+}
+
+JSBool
+js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
+{
+ char *last;
+ JSStackFrame *fp;
+ JSErrorReport report;
+ JSBool warning;
+
+ if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
+ return JS_TRUE;
+
+ last = JS_vsmprintf(format, ap);
+ if (!last)
+ return JS_FALSE;
+
+ memset(&report, 0, sizeof (struct JSErrorReport));
+ report.flags = flags;
+
+ /* Find the top-most active script frame, for best line number blame. */
+ for (fp = cx->fp; fp; fp = fp->down) {
+ if (fp->script && fp->pc) {
+ report.filename = fp->script->filename;
+ report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+ break;
+ }
+ }
+
+ warning = JSREPORT_IS_WARNING(report.flags);
+ if (warning && JS_HAS_WERROR_OPTION(cx)) {
+ report.flags &= ~JSREPORT_WARNING;
+ warning = JS_FALSE;
+ }
+
+ ReportError(cx, last, &report);
+ free(last);
+ return warning;
+}
+
+/*
+ * The arguments from ap need to be packaged up into an array and stored
+ * into the report struct.
+ *
+ * The format string addressed by the error number may contain operands
+ * identified by the format {N}, where N is a decimal digit. Each of these
+ * is to be replaced by the Nth argument from the va_list. The complete
+ * message is placed into reportp->ucmessage converted to a JSString.
+ *
+ * Returns true if the expansion succeeds (can fail if out of memory).
+ */
+JSBool
+js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
+ void *userRef, const uintN errorNumber,
+ char **messagep, JSErrorReport *reportp,
+ JSBool *warningp, JSBool charArgs, va_list ap)
+{
+ const JSErrorFormatString *efs;
+ int i;
+ int argCount;
+
+ *warningp = JSREPORT_IS_WARNING(reportp->flags);
+ if (*warningp && JS_HAS_WERROR_OPTION(cx)) {
+ reportp->flags &= ~JSREPORT_WARNING;
+ *warningp = JS_FALSE;
+ }
+
+ *messagep = NULL;
+ if (callback) {
+ efs = callback(userRef, NULL, errorNumber);
+ if (efs) {
+ size_t totalArgsLength = 0;
+ size_t argLengths[10]; /* only {0} thru {9} supported */
+ argCount = efs->argCount;
+ JS_ASSERT(argCount <= 10);
+ if (argCount > 0) {
+ /*
+ * Gather the arguments into an array, and accumulate
+ * their sizes. We allocate 1 more than necessary and
+ * null it out to act as the caboose when we free the
+ * pointers later.
+ */
+ reportp->messageArgs = (const jschar **)
+ JS_malloc(cx, sizeof(jschar *) * (argCount + 1));
+ if (!reportp->messageArgs)
+ return JS_FALSE;
+ reportp->messageArgs[argCount] = NULL;
+ for (i = 0; i < argCount; i++) {
+ if (charArgs) {
+ char *charArg = va_arg(ap, char *);
+ reportp->messageArgs[i]
+ = js_InflateString(cx, charArg, strlen(charArg));
+ if (!reportp->messageArgs[i])
+ goto error;
+ }
+ else
+ reportp->messageArgs[i] = va_arg(ap, jschar *);
+ argLengths[i] = js_strlen(reportp->messageArgs[i]);
+ totalArgsLength += argLengths[i];
+ }
+ /* NULL-terminate for easy copying. */
+ reportp->messageArgs[i] = NULL;
+ }
+ /*
+ * Parse the error format, substituting the argument X
+ * for {X} in the format.
+ */
+ if (argCount > 0) {
+ if (efs->format) {
+ const char *fmt;
+ const jschar *arg;
+ jschar *out;
+ int expandedArgs = 0;
+ size_t expandedLength
+ = strlen(efs->format)
+ - (3 * argCount) /* exclude the {n} */
+ + totalArgsLength;
+ /*
+ * Note - the above calculation assumes that each argument
+ * is used once and only once in the expansion !!!
+ */
+ reportp->ucmessage = out = (jschar *)
+ JS_malloc(cx, (expandedLength + 1) * sizeof(jschar));
+ if (!out)
+ goto error;
+ fmt = efs->format;
+ while (*fmt) {
+ if (*fmt == '{') {
+ if (isdigit(fmt[1])) {
+ int d = JS7_UNDEC(fmt[1]);
+ JS_ASSERT(expandedArgs < argCount);
+ arg = reportp->messageArgs[d];
+ js_strncpy(out, arg, argLengths[d]);
+ out += argLengths[d];
+ fmt += 3;
+ expandedArgs++;
+ continue;
+ }
+ }
+ /*
+ * is this kosher?
+ */
+ *out++ = (unsigned char)(*fmt++);
+ }
+ JS_ASSERT(expandedArgs == argCount);
+ *out = 0;
+ *messagep =
+ js_DeflateString(cx, reportp->ucmessage,
+ (size_t)(out - reportp->ucmessage));
+ if (!*messagep)
+ goto error;
+ }
+ } else {
+ /*
+ * Zero arguments: the format string (if it exists) is the
+ * entire message.
+ */
+ if (efs->format) {
+ *messagep = JS_strdup(cx, efs->format);
+ if (!*messagep)
+ goto error;
+ reportp->ucmessage
+ = js_InflateString(cx, *messagep, strlen(*messagep));
+ if (!reportp->ucmessage)
+ goto error;
+ }
+ }
+ }
+ }
+ if (*messagep == NULL) {
+ /* where's the right place for this ??? */
+ const char *defaultErrorMessage
+ = "No error message available for error number %d";
+ size_t nbytes = strlen(defaultErrorMessage) + 16;
+ *messagep = (char *)JS_malloc(cx, nbytes);
+ if (!*messagep)
+ goto error;
+ JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
+ }
+ return JS_TRUE;
+
+error:
+ if (reportp->messageArgs) {
+ i = 0;
+ while (reportp->messageArgs[i])
+ JS_free(cx, (void *)reportp->messageArgs[i++]);
+ JS_free(cx, (void *)reportp->messageArgs);
+ reportp->messageArgs = NULL;
+ }
+ if (reportp->ucmessage) {
+ JS_free(cx, (void *)reportp->ucmessage);
+ reportp->ucmessage = NULL;
+ }
+ if (*messagep) {
+ JS_free(cx, (void *)*messagep);
+ *messagep = NULL;
+ }
+ return JS_FALSE;
+}
+
+JSBool
+js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
+ void *userRef, const uintN errorNumber,
+ JSBool charArgs, va_list ap)
+{
+ JSStackFrame *fp;
+ JSErrorReport report;
+ char *message;
+ JSBool warning;
+
+ if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
+ return JS_TRUE;
+
+ memset(&report, 0, sizeof (struct JSErrorReport));
+ report.flags = flags;
+ report.errorNumber = errorNumber;
+
+ /*
+ * If we can't find out where the error was based on the current frame,
+ * see if the next frame has a script/pc combo we can use.
+ */
+ for (fp = cx->fp; fp; fp = fp->down) {
+ if (fp->script && fp->pc) {
+ report.filename = fp->script->filename;
+ report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+ break;
+ }
+ }
+
+ if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
+ &message, &report, &warning, charArgs, ap)) {
+ return JS_FALSE;
+ }
+
+ ReportError(cx, message, &report);
+
+ if (message)
+ JS_free(cx, message);
+ if (report.messageArgs) {
+ int i = 0;
+ while (report.messageArgs[i])
+ JS_free(cx, (void *)report.messageArgs[i++]);
+ JS_free(cx, (void *)report.messageArgs);
+ }
+ if (report.ucmessage)
+ JS_free(cx, (void *)report.ucmessage);
+
+ return warning;
+}
+
+JS_FRIEND_API(void)
+js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
+{
+ JSErrorReporter onError;
+
+ if (!message)
+ return;
+
+ if (cx->lastMessage)
+ free(cx->lastMessage);
+ cx->lastMessage = JS_strdup(cx, message);
+ if (!cx->lastMessage)
+ return;
+ onError = cx->errorReporter;
+
+ /*
+ * If debugErrorHook is present then we give it a chance to veto
+ * sending the error on to the regular ErrorReporter.
+ */
+ if (onError) {
+ JSDebugErrorHook hook = cx->runtime->debugErrorHook;
+ if (hook &&
+ !hook(cx, cx->lastMessage, reportp,
+ cx->runtime->debugErrorHookData)) {
+ onError = NULL;
+ }
+ }
+ if (onError)
+ onError(cx, cx->lastMessage, reportp);
+}
+
+void
+js_ReportIsNotDefined(JSContext *cx, const char *name)
+{
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
+}
+
+#if defined DEBUG && defined XP_UNIX
+/* For gdb usage. */
+void js_traceon(JSContext *cx) { cx->tracefp = stderr; }
+void js_traceoff(JSContext *cx) { cx->tracefp = NULL; }
+#endif
+
+JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
+#if JS_HAS_DFLT_MSG_STRINGS
+#define MSG_DEF(name, number, count, exception, format) \
+ { format, count } ,
+#else
+#define MSG_DEF(name, number, count, exception, format) \
+ { NULL, count } ,
+#endif
+#include "js.msg"
+#undef MSG_DEF
+};
+
+const JSErrorFormatString *
+js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
+{
+ if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
+ return &js_ErrorFormatString[errorNumber];
+ return NULL;
+}
diff --git a/src/dom/js/jscntxt.h b/src/dom/js/jscntxt.h
new file mode 100644
index 000000000..f9aab41a8
--- /dev/null
+++ b/src/dom/js/jscntxt.h
@@ -0,0 +1,496 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jscntxt_h___
+#define jscntxt_h___
+/*
+ * JS execution context.
+ */
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsclist.h"
+#include "jslong.h"
+#include "jsatom.h"
+#include "jsconfig.h"
+#include "jsdhash.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jsobj.h"
+#include "jsprvtd.h"
+#include "jspubtd.h"
+#include "jsregexp.h"
+
+JS_BEGIN_EXTERN_C
+
+typedef enum JSGCMode { JS_NO_GC, JS_MAYBE_GC, JS_FORCE_GC } JSGCMode;
+
+typedef enum JSRuntimeState {
+ JSRTS_DOWN,
+ JSRTS_LAUNCHING,
+ JSRTS_UP,
+ JSRTS_LANDING
+} JSRuntimeState;
+
+typedef struct JSPropertyTreeEntry {
+ JSDHashEntryHdr hdr;
+ JSScopeProperty *child;
+} JSPropertyTreeEntry;
+
+struct JSRuntime {
+ /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
+ JSRuntimeState state;
+
+ /* Garbage collector state, used by jsgc.c. */
+ JSArenaPool gcArenaPool;
+ JSDHashTable gcRootsHash;
+ JSDHashTable *gcLocksHash;
+ JSGCThing *gcFreeList;
+ jsrefcount gcKeepAtoms;
+ uint32 gcBytes;
+ uint32 gcLastBytes;
+ uint32 gcMaxBytes;
+ uint32 gcLevel;
+ uint32 gcNumber;
+ JSPackedBool gcPoke;
+ JSPackedBool gcRunning;
+ JSGCCallback gcCallback;
+ uint32 gcMallocBytes;
+#ifdef JS_GCMETER
+ JSGCStats gcStats;
+#endif
+
+ /* Literal table maintained by jsatom.c functions. */
+ JSAtomState atomState;
+
+ /* Random number generator state, used by jsmath.c. */
+ JSBool rngInitialized;
+ int64 rngMultiplier;
+ int64 rngAddend;
+ int64 rngMask;
+ int64 rngSeed;
+ jsdouble rngDscale;
+
+ /* Well-known numbers held for use by this runtime's contexts. */
+ jsdouble *jsNaN;
+ jsdouble *jsNegativeInfinity;
+ jsdouble *jsPositiveInfinity;
+
+ /* Empty string held for use by this runtime's contexts. */
+ JSString *emptyString;
+
+ /* List of active contexts sharing this runtime; protected by gcLock. */
+ JSCList contextList;
+
+ /* These are used for debugging -- see jsprvtd.h and jsdbgapi.h. */
+ JSTrapHandler interruptHandler;
+ void *interruptHandlerData;
+ JSNewScriptHook newScriptHook;
+ void *newScriptHookData;
+ JSDestroyScriptHook destroyScriptHook;
+ void *destroyScriptHookData;
+ JSTrapHandler debuggerHandler;
+ void *debuggerHandlerData;
+ JSSourceHandler sourceHandler;
+ void *sourceHandlerData;
+ JSInterpreterHook executeHook;
+ void *executeHookData;
+ JSInterpreterHook callHook;
+ void *callHookData;
+ JSObjectHook objectHook;
+ void *objectHookData;
+ JSTrapHandler throwHook;
+ void *throwHookData;
+ JSDebugErrorHook debugErrorHook;
+ void *debugErrorHookData;
+
+ /* More debugging state, see jsdbgapi.c. */
+ JSCList trapList;
+ JSCList watchPointList;
+
+ /* Weak links to properties, indexed by quickened get/set opcodes. */
+ /* XXX must come after JSCLists or MSVC alignment bug bites empty lists */
+ JSPropertyCache propertyCache;
+
+ /* Client opaque pointer */
+ void *data;
+
+#ifdef JS_THREADSAFE
+ /* These combine to interlock the GC and new requests. */
+ PRLock *gcLock;
+ PRCondVar *gcDone;
+ PRCondVar *requestDone;
+ uint32 requestCount;
+ jsword gcThread;
+
+ /* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
+ PRLock *rtLock;
+#ifdef DEBUG
+ jsword rtLockOwner;
+#endif
+
+ /* Used to synchronize down/up state change; protected by gcLock. */
+ PRCondVar *stateChange;
+
+ /* Used to serialize cycle checks when setting __proto__ or __parent__. */
+ PRLock *setSlotLock;
+ PRCondVar *setSlotDone;
+ JSBool setSlotBusy;
+ JSScope *setSlotScope; /* deadlock avoidance, see jslock.c */
+
+ /*
+ * State for sharing single-threaded scopes, once a second thread tries to
+ * lock a scope. The scopeSharingDone condvar is protected by rt->gcLock,
+ * to minimize number of locks taken in JS_EndRequest.
+ *
+ * The scopeSharingTodo linked list is likewise "global" per runtime, not
+ * one-list-per-context, to conserve space over all contexts, optimizing
+ * for the likely case that scopes become shared rarely, and among a very
+ * small set of threads (contexts).
+ */
+ PRCondVar *scopeSharingDone;
+ JSScope *scopeSharingTodo;
+
+/*
+ * Magic terminator for the rt->scopeSharingTodo linked list, threaded through
+ * scope->u.link. This hack allows us to test whether a scope is on the list
+ * by asking whether scope->u.link is non-null. We use a large, likely bogus
+ * pointer here to distinguish this value from any valid u.count (small int)
+ * value.
+ */
+#define NO_SCOPE_SHARING_TODO ((JSScope *) 0xfeedbeef)
+#endif /* JS_THREADSAFE */
+
+ /*
+ * Check property accessibility for objects of arbitrary class. Used at
+ * present to check f.caller accessibility for any function object f.
+ */
+ JSCheckAccessOp checkObjectAccess;
+
+ /* Security principals serialization support. */
+ JSPrincipalsTranscoder principalsTranscoder;
+
+ /* Shared scope property tree, and allocator for its nodes. */
+ JSDHashTable propertyTreeHash;
+ JSScopeProperty *propertyFreeList;
+ JSArenaPool propertyArenaPool;
+
+#ifdef DEBUG
+ /* Function invocation metering. */
+ jsrefcount inlineCalls;
+ jsrefcount nativeCalls;
+ jsrefcount nonInlineCalls;
+ jsrefcount constructs;
+
+ /* Scope lock and property metering. */
+ jsrefcount claimAttempts;
+ jsrefcount claimedScopes;
+ jsrefcount deadContexts;
+ jsrefcount deadlocksAvoided;
+ jsrefcount liveScopes;
+ jsrefcount sharedScopes;
+ jsrefcount totalScopes;
+ jsrefcount badUndependStrings;
+ jsrefcount liveScopeProps;
+ jsrefcount totalScopeProps;
+ jsrefcount livePropTreeNodes;
+ jsrefcount duplicatePropTreeNodes;
+ jsrefcount totalPropTreeNodes;
+ jsrefcount propTreeKidsChunks;
+ jsrefcount middleDeleteFixups;
+
+ /* String instrumentation. */
+ jsrefcount liveStrings;
+ jsrefcount totalStrings;
+ jsrefcount liveDependentStrings;
+ jsrefcount totalDependentStrings;
+ double lengthSum;
+ double lengthSquaredSum;
+ double strdepLengthSum;
+ double strdepLengthSquaredSum;
+#endif
+};
+
+#ifdef DEBUG
+# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
+# define JS_RUNTIME_UNMETER(rt, which) JS_ATOMIC_DECREMENT(&(rt)->which)
+#else
+# define JS_RUNTIME_METER(rt, which) /* nothing */
+# define JS_RUNTIME_UNMETER(rt, which) /* nothing */
+#endif
+
+#define JS_KEEP_ATOMS(rt) JS_ATOMIC_INCREMENT(&(rt)->gcKeepAtoms);
+#define JS_UNKEEP_ATOMS(rt) JS_ATOMIC_DECREMENT(&(rt)->gcKeepAtoms);
+
+#ifdef JS_ARGUMENT_FORMATTER_DEFINED
+/*
+ * Linked list mapping format strings for JS_{Convert,Push}Arguments{,VA} to
+ * formatter functions. Elements are sorted in non-increasing format string
+ * length order.
+ */
+struct JSArgumentFormatMap {
+ const char *format;
+ size_t length;
+ JSArgumentFormatter formatter;
+ JSArgumentFormatMap *next;
+};
+#endif
+
+struct JSStackHeader {
+ uintN nslots;
+ JSStackHeader *down;
+};
+
+#define JS_STACK_SEGMENT(sh) ((jsval *)(sh) + 2)
+
+/*
+ * Key and entry types for the JSContext.resolvingTable hash table, typedef'd
+ * here because all consumers need to see these declarations (and not just the
+ * typedef names, as would be the case for an opaque pointer-to-typedef'd-type
+ * declaration), along with cx->resolvingTable.
+ */
+typedef struct JSResolvingKey {
+ JSObject *obj;
+ jsid id;
+} JSResolvingKey;
+
+typedef struct JSResolvingEntry {
+ JSDHashEntryHdr hdr;
+ JSResolvingKey key;
+ uint32 flags;
+} JSResolvingEntry;
+
+#define JSRESFLAG_LOOKUP 0x1 /* resolving id from lookup */
+#define JSRESFLAG_WATCH 0x2 /* resolving id from watch */
+
+struct JSContext {
+ JSCList links;
+
+ /* Interpreter activation count. */
+ uintN interpLevel;
+
+ /* Limit pointer for checking stack consumption during recursion. */
+ jsuword stackLimit;
+
+ /* Runtime version control identifier and equality operators. */
+ JSVersion version;
+ jsbytecode jsop_eq;
+ jsbytecode jsop_ne;
+
+ /* Data shared by threads in an address space. */
+ JSRuntime *runtime;
+
+ /* Stack arena pool and frame pointer register. */
+ JSArenaPool stackPool;
+ JSStackFrame *fp;
+
+ /* Temporary arena pool used while compiling and decompiling. */
+ JSArenaPool tempPool;
+
+ /* Top-level object and pointer to top stack frame's scope chain. */
+ JSObject *globalObject;
+
+ /* Most recently created things by type, members of the GC's root set. */
+ JSGCThing *newborn[GCX_NTYPES];
+
+ /* Atom root for the last-looked-up atom on this context. */
+ JSAtom *lastAtom;
+
+ /* Regular expression class statics (XXX not shared globally). */
+ JSRegExpStatics regExpStatics;
+
+ /* State for object and array toSource conversion. */
+ JSSharpObjectMap sharpObjectMap;
+
+ /* Argument formatter support for JS_{Convert,Push}Arguments{,VA}. */
+ JSArgumentFormatMap *argumentFormatMap;
+
+ /* Last message string and trace file for debugging. */
+ char *lastMessage;
+#ifdef DEBUG
+ void *tracefp;
+#endif
+
+ /* Per-context optional user callbacks. */
+ JSBranchCallback branchCallback;
+ JSErrorReporter errorReporter;
+
+ /* Client opaque pointer */
+ void *data;
+
+ /* GC and thread-safe state. */
+ JSStackFrame *dormantFrameChain; /* dormant stack frame to scan */
+#ifdef JS_THREADSAFE
+ jsword thread;
+ jsrefcount requestDepth;
+ JSScope *scopeToShare; /* weak reference, see jslock.c */
+ JSScope *lockedSealedScope; /* weak ref, for low-cost sealed
+ scope locking */
+#endif
+
+#if JS_HAS_LVALUE_RETURN
+ /*
+ * Secondary return value from native method called on the left-hand side
+ * of an assignment operator. The native should store the object in which
+ * to set a property in *rval, and return the property's id expressed as a
+ * jsval by calling JS_SetCallReturnValue2(cx, idval).
+ */
+ jsval rval2;
+ JSPackedBool rval2set;
+#endif
+
+ /*
+ * True if creating an exception object, to prevent runaway recursion.
+ * NB: creatingException packs with rval2set, #if JS_HAS_LVALUE_RETURN,
+ * and with throwing, below.
+ */
+ JSPackedBool creatingException;
+
+ /*
+ * Exception state -- the exception member is a GC root by definition.
+ * NB: throwing packs with creatingException and rval2set, above.
+ */
+ JSPackedBool throwing; /* is there a pending exception? */
+ jsval exception; /* most-recently-thrown exception */
+
+ /* Per-context options. */
+ uint32 options; /* see jsapi.h for JSOPTION_* */
+
+ /* Locale specific callbacks for string conversion. */
+ JSLocaleCallbacks *localeCallbacks;
+
+ /*
+ * cx->resolvingTable is non-null and non-empty if we are initializing
+ * standard classes lazily, or if we are otherwise recursing indirectly
+ * from js_LookupProperty through a JSClass.resolve hook. It is used to
+ * limit runaway recursion (see jsapi.c and jsobj.c).
+ */
+ JSDHashTable *resolvingTable;
+
+ /* PDL of stack headers describing stack slots not rooted by argv, etc. */
+ JSStackHeader *stackHeaders;
+
+ /* Optional hook to find principals for an object being accessed on cx. */
+ JSObjectPrincipalsFinder findObjectPrincipals;
+};
+
+/* Slightly more readable macros, also to hide bitset implementation detail. */
+#define JS_HAS_STRICT_OPTION(cx) ((cx)->options & JSOPTION_STRICT)
+#define JS_HAS_WERROR_OPTION(cx) ((cx)->options & JSOPTION_WERROR)
+
+extern JSContext *
+js_NewContext(JSRuntime *rt, size_t stackChunkSize);
+
+extern void
+js_DestroyContext(JSContext *cx, JSGCMode gcmode);
+
+/*
+ * Return true if cx points to a context in rt->contextList, else return false.
+ * NB: the caller (see jslock.c:ClaimScope) must hold rt->gcLock.
+ */
+extern JSBool
+js_ValidContextPointer(JSRuntime *rt, JSContext *cx);
+
+/*
+ * If unlocked, acquire and release rt->gcLock around *iterp update; otherwise
+ * the caller must be holding rt->gcLock.
+ */
+extern JSContext *
+js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp);
+
+/*
+ * Report an exception, which is currently realized as a printf-style format
+ * string and its arguments.
+ */
+typedef enum JSErrNum {
+#define MSG_DEF(name, number, count, exception, format) \
+ name = number,
+#include "js.msg"
+#undef MSG_DEF
+ JSErr_Limit
+} JSErrNum;
+
+extern const JSErrorFormatString *
+js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber);
+
+#ifdef va_start
+extern JSBool
+js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap);
+
+extern JSBool
+js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
+ void *userRef, const uintN errorNumber,
+ JSBool charArgs, va_list ap);
+
+extern JSBool
+js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
+ void *userRef, const uintN errorNumber,
+ char **message, JSErrorReport *reportp,
+ JSBool *warningp, JSBool charArgs, va_list ap);
+#endif
+
+extern void
+js_ReportOutOfMemory(JSContext *cx, JSErrorCallback errorCallback);
+
+/*
+ * Report an exception using a previously composed JSErrorReport.
+ * XXXbe remove from "friend" API
+ */
+extern JS_FRIEND_API(void)
+js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *report);
+
+extern void
+js_ReportIsNotDefined(JSContext *cx, const char *name);
+
+extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
+
+/*
+ * See JS_SetThreadStackLimit in jsapi.c, where we check that the stack grows
+ * in the expected direction. On Unix-y systems, JS_STACK_GROWTH_DIRECTION is
+ * computed on the build host by jscpucfg.c and written into jsautocfg.h. The
+ * macro is hardcoded in jscpucfg.h on Windows and Mac systems (for historical
+ * reasons pre-dating autoconf usage).
+ */
+#if JS_STACK_GROWTH_DIRECTION > 0
+# define JS_CHECK_STACK_SIZE(cx, lval) ((jsuword)&(lval) < (cx)->stackLimit)
+#else
+# define JS_CHECK_STACK_SIZE(cx, lval) ((jsuword)&(lval) > (cx)->stackLimit)
+#endif
+
+JS_END_EXTERN_C
+
+#endif /* jscntxt_h___ */
diff --git a/src/dom/js/jscompat.h b/src/dom/js/jscompat.h
new file mode 100644
index 000000000..6ba036a5e
--- /dev/null
+++ b/src/dom/js/jscompat.h
@@ -0,0 +1,57 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* -*- Mode: C; tab-width: 8 -*-
+ * Copyright © 1996-1999 Netscape Communications Corporation, All Rights Reserved.
+ */
+#ifndef jscompat_h___
+#define jscompat_h___
+/*
+ * Compatibility glue for various NSPR versions. We must always define int8,
+ * int16, jsword, and so on to minimize differences with js/ref, no matter what
+ * the NSPR typedef names may be.
+ */
+#include "jstypes.h"
+#include "jslong.h"
+
+typedef JSIntn intN;
+typedef JSUintn uintN;
+typedef JSUword jsuword;
+typedef JSWord jsword;
+typedef float float32;
+#define allocPriv allocPool
+#endif /* jscompat_h___ */
diff --git a/src/dom/js/jsconfig.h b/src/dom/js/jsconfig.h
new file mode 100644
index 000000000..fae86d3a7
--- /dev/null
+++ b/src/dom/js/jsconfig.h
@@ -0,0 +1,489 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS configuration macros.
+ */
+#ifndef JS_VERSION
+#define JS_VERSION 150
+#endif
+
+/*
+ * Compile-time JS version configuration. The JS version numbers lie on the
+ * number line like so:
+ *
+ * 1.0 1.1 1.2 1.3 1.4 ECMAv3 1.5
+ * ^ ^
+ * | |
+ * basis for ECMAv1 close to ECMAv2
+ *
+ * where ECMAv3 stands for ECMA-262 Edition 3. See the runtime version enum
+ * JSVersion in jspubtd.h. Code in the engine can therefore count on version
+ * <= JSVERSION_1_4 to mean "before the Third Edition of ECMA-262" and version
+ * > JSVERSION_1_4 to mean "at or after the Third Edition".
+ *
+ * In the unlikely event that SpiderMonkey ever implements JavaScript 2.0, or
+ * ECMA-262 Edition 4 (JS2 without certain extensions), the version number to
+ * use would be near 200, or greater.
+ *
+ * The JS_VERSION_ECMA_3 version is the minimal configuration conforming to
+ * the ECMA-262 Edition 3 specification. Use it for minimal embeddings, where
+ * you're sure you don't need any of the extensions disabled in this version.
+ * In order to facilitate testing, JS_HAS_OBJ_PROTO_PROP is defined as part of
+ * the JS_VERSION_ECMA_3_TEST version.
+ */
+#define JS_VERSION_ECMA_3 148
+#define JS_VERSION_ECMA_3_TEST 149
+
+#if JS_VERSION == JS_VERSION_ECMA_3 || \
+ JS_VERSION == JS_VERSION_ECMA_3_TEST
+
+#define JS_BUG_NULL_INDEX_PROPS 0 /* o[0] defaults to null, not void */
+#define JS_BUG_EMPTY_INDEX_ZERO 0 /* o[""] is equivalent to o[0] */
+#define JS_BUG_EAGER_TOSTRING 0 /* o.toString() trumps o.valueOf() */
+#define JS_BUG_VOID_TOSTRING 0 /* void 0 + 0 == "undefined0" */
+#define JS_BUG_EVAL_THIS_FUN 0 /* eval('this') in function f is f */
+#define JS_BUG_EVAL_THIS_SCOPE 0 /* Math.eval('sin(x)') vs. local x */
+#define JS_BUG_FALLIBLE_EQOPS 0 /* fallible/intransitive equality ops */
+#define JS_BUG_FALLIBLE_TONUM 0 /* fallible ValueToNumber primitive */
+#define JS_BUG_WITH_CLOSURE 0 /* with(o)function f(){} sets o.f */
+
+#define JS_HAS_PROP_DELETE 1 /* delete o.p removes p from o */
+#define JS_HAS_CALL_OBJECT 1 /* fun.caller is stack frame obj */
+#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */
+#define JS_HAS_DO_WHILE_LOOP 1 /* has do {...} while (b) */
+#define JS_HAS_SWITCH_STATEMENT 1 /* has switch (v) {case c: ...} */
+#define JS_HAS_SOME_PERL_FUN 1 /* has array.join/reverse/sort */
+#define JS_HAS_MORE_PERL_FUN 1 /* has array.push, array.pop, etc */
+#define JS_HAS_STR_HTML_HELPERS 0 /* has str.anchor, str.bold, etc. */
+#define JS_HAS_PERL_SUBSTR 0 /* has str.substr */
+#define JS_HAS_VALUEOF_HINT 1 /* valueOf(hint) where hint is typeof */
+#define JS_HAS_LEXICAL_CLOSURE 1 /* nested functions, lexically closed */
+#define JS_HAS_APPLY_FUNCTION 1 /* has fun.apply(obj, argArray) */
+#define JS_HAS_CALL_FUNCTION 1 /* has fun.call(obj, arg1, ... argN) */
+#if JS_VERSION == JS_VERSION_ECMA_3_TEST
+#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
+#else
+#define JS_HAS_OBJ_PROTO_PROP 0 /* has o.__proto__ etc. */
+#endif
+#define JS_HAS_REGEXPS 1 /* has perl r.e.s via RegExp, /pat/ */
+#define JS_HAS_SEQUENCE_OPS 1 /* has array.slice, string.concat */
+#define JS_HAS_INITIALIZERS 1 /* has var o = {'foo': 42, 'bar':3} */
+#define JS_HAS_OBJ_WATCHPOINT 0 /* has o.watch and o.unwatch */
+#define JS_HAS_EXPORT_IMPORT 0 /* has export fun; import obj.fun */
+#define JS_HAS_EVAL_THIS_SCOPE 0 /* Math.eval is same as with (Math) */
+#define JS_HAS_TRIPLE_EQOPS 1 /* has === and !== identity eqops */
+#define JS_HAS_SHARP_VARS 0 /* has #n=, #n# for object literals */
+#define JS_HAS_REPLACE_LAMBDA 1 /* has string.replace(re, lambda) */
+#define JS_HAS_SCRIPT_OBJECT 0 /* has (new Script("x++")).exec() */
+#define JS_HAS_XDR 0 /* has XDR API and internal support */
+#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */
+#define JS_HAS_EXCEPTIONS 1 /* has exception handling */
+#define JS_HAS_UNDEFINED 1 /* has global "undefined" property */
+#define JS_HAS_TOSOURCE 0 /* has Object/Array toSource method */
+#define JS_HAS_IN_OPERATOR 1 /* has in operator ('p' in {p:1}) */
+#define JS_HAS_INSTANCEOF 1 /* has {p:1} instanceof Object */
+#define JS_HAS_ARGS_OBJECT 1 /* has minimal ECMA arguments object */
+#define JS_HAS_DEBUGGER_KEYWORD 0 /* has hook for debugger keyword */
+#define JS_HAS_ERROR_EXCEPTIONS 1 /* has error object hierarchy */
+#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
+#define JS_HAS_NEW_OBJ_METHODS 1 /* has Object.prototype query methods */
+#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
+#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
+#define JS_HAS_NUMBER_FORMATS 1 /* numbers have formatting methods */
+#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
+#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */
+#define JS_HAS_CONST 0 /* has JS2 const as alternative var */
+#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */
+#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */
+#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
+
+#elif JS_VERSION == 100
+
+#define JS_BUG_NULL_INDEX_PROPS 1 /* o[0] defaults to null, not void */
+#define JS_BUG_EMPTY_INDEX_ZERO 1 /* o[""] is equivalent to o[0] */
+#define JS_BUG_EAGER_TOSTRING 1 /* o.toString() trumps o.valueOf() */
+#define JS_BUG_VOID_TOSTRING 0 /* void 0 + 0 == "undefined0" */
+#define JS_BUG_EVAL_THIS_FUN 0 /* eval('this') in function f is f */
+#define JS_BUG_EVAL_THIS_SCOPE 0 /* Math.eval('sin(x)') vs. local x */
+#define JS_BUG_FALLIBLE_EQOPS 1 /* fallible/intransitive equality ops */
+#define JS_BUG_FALLIBLE_TONUM 1 /* fallible ValueToNumber primitive */
+#define JS_BUG_WITH_CLOSURE 0 /* with(o)function f(){} sets o.f */
+
+#define JS_HAS_PROP_DELETE 0 /* delete o.p removes p from o */
+#define JS_HAS_CALL_OBJECT 0 /* fun.caller is stack frame obj */
+#define JS_HAS_LABEL_STATEMENT 0 /* has break/continue to label: */
+#define JS_HAS_DO_WHILE_LOOP 0 /* has do {...} while (b) */
+#define JS_HAS_SWITCH_STATEMENT 0 /* has switch (v) {case c: ...} */
+#define JS_HAS_SOME_PERL_FUN 0 /* has array.join/reverse/sort */
+#define JS_HAS_MORE_PERL_FUN 0 /* has array.push, str.substr, etc */
+#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
+#define JS_HAS_PERL_SUBSTR 0 /* has str.substr */
+#define JS_HAS_VALUEOF_HINT 0 /* valueOf(hint) where hint is typeof */
+#define JS_HAS_LEXICAL_CLOSURE 0 /* nested functions, lexically closed */
+#define JS_HAS_APPLY_FUNCTION 0 /* has fun.apply(obj, argArray) */
+#define JS_HAS_CALL_FUNCTION 0 /* has fun.call(obj, arg1, ... argN) */
+#define JS_HAS_OBJ_PROTO_PROP 0 /* has o.__proto__ etc. */
+#define JS_HAS_REGEXPS 0 /* has perl r.e.s via RegExp, /pat/ */
+#define JS_HAS_SEQUENCE_OPS 0 /* has array.slice, string.concat */
+#define JS_HAS_INITIALIZERS 0 /* has var o = {'foo': 42, 'bar':3} */
+#define JS_HAS_OBJ_WATCHPOINT 0 /* has o.watch and o.unwatch */
+#define JS_HAS_EXPORT_IMPORT 0 /* has export fun; import obj.fun */
+#define JS_HAS_EVAL_THIS_SCOPE 0 /* Math.eval is same as with (Math) */
+#define JS_HAS_TRIPLE_EQOPS 0 /* has === and !== identity eqops */
+#define JS_HAS_SHARP_VARS 0 /* has #n=, #n# for object literals */
+#define JS_HAS_REPLACE_LAMBDA 0 /* has string.replace(re, lambda) */
+#define JS_HAS_SCRIPT_OBJECT 0 /* has (new Script("x++")).exec() */
+#define JS_HAS_XDR 0 /* has XDR API and internal support */
+#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */
+#define JS_HAS_EXCEPTIONS 0 /* has exception handling */
+#define JS_HAS_UNDEFINED 0 /* has global "undefined" property */
+#define JS_HAS_TOSOURCE 0 /* has Object/Array toSource method */
+#define JS_HAS_IN_OPERATOR 0 /* has in operator ('p' in {p:1}) */
+#define JS_HAS_INSTANCEOF 0 /* has {p:1} instanceof Object */
+#define JS_HAS_ARGS_OBJECT 0 /* has minimal ECMA arguments object */
+#define JS_HAS_DEBUGGER_KEYWORD 0 /* has hook for debugger keyword */
+#define JS_HAS_ERROR_EXCEPTIONS 0 /* has error object hierarchy */
+#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
+#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
+#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
+#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
+#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
+#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
+#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */
+#define JS_HAS_CONST 0 /* has JS2 const as alternative var */
+#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */
+#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
+#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
+
+#elif JS_VERSION == 110
+
+#define JS_BUG_NULL_INDEX_PROPS 1 /* o[0] defaults to null, not void */
+#define JS_BUG_EMPTY_INDEX_ZERO 1 /* o[""] is equivalent to o[0] */
+#define JS_BUG_EAGER_TOSTRING 1 /* o.toString() trumps o.valueOf() */
+#define JS_BUG_VOID_TOSTRING 0 /* void 0 + 0 == "undefined0" */
+#define JS_BUG_EVAL_THIS_FUN 1 /* eval('this') in function f is f */
+#define JS_BUG_EVAL_THIS_SCOPE 1 /* Math.eval('sin(x)') vs. local x */
+#define JS_BUG_FALLIBLE_EQOPS 1 /* fallible/intransitive equality ops */
+#define JS_BUG_FALLIBLE_TONUM 1 /* fallible ValueToNumber primitive */
+#define JS_BUG_WITH_CLOSURE 0 /* with(o)function f(){} sets o.f */
+
+#define JS_HAS_PROP_DELETE 0 /* delete o.p removes p from o */
+#define JS_HAS_CALL_OBJECT 0 /* fun.caller is stack frame obj */
+#define JS_HAS_LABEL_STATEMENT 0 /* has break/continue to label: */
+#define JS_HAS_DO_WHILE_LOOP 0 /* has do {...} while (b) */
+#define JS_HAS_SWITCH_STATEMENT 0 /* has switch (v) {case c: ...} */
+#define JS_HAS_SOME_PERL_FUN 1 /* has array.join/reverse/sort */
+#define JS_HAS_MORE_PERL_FUN 0 /* has array.push, str.substr, etc */
+#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
+#define JS_HAS_PERL_SUBSTR 0 /* has str.substr */
+#define JS_HAS_VALUEOF_HINT 0 /* valueOf(hint) where hint is typeof */
+#define JS_HAS_LEXICAL_CLOSURE 0 /* nested functions, lexically closed */
+#define JS_HAS_APPLY_FUNCTION 0 /* has apply(fun, arg1, ... argN) */
+#define JS_HAS_CALL_FUNCTION 0 /* has fun.call(obj, arg1, ... argN) */
+#define JS_HAS_OBJ_PROTO_PROP 0 /* has o.__proto__ etc. */
+#define JS_HAS_REGEXPS 0 /* has perl r.e.s via RegExp, /pat/ */
+#define JS_HAS_SEQUENCE_OPS 0 /* has array.slice, string.concat */
+#define JS_HAS_INITIALIZERS 0 /* has var o = {'foo': 42, 'bar':3} */
+#define JS_HAS_OBJ_WATCHPOINT 0 /* has o.watch and o.unwatch */
+#define JS_HAS_EXPORT_IMPORT 0 /* has export fun; import obj.fun */
+#define JS_HAS_EVAL_THIS_SCOPE 0 /* Math.eval is same as with (Math) */
+#define JS_HAS_TRIPLE_EQOPS 0 /* has === and !== identity eqops */
+#define JS_HAS_SHARP_VARS 0 /* has #n=, #n# for object literals */
+#define JS_HAS_REPLACE_LAMBDA 0 /* has string.replace(re, lambda) */
+#define JS_HAS_SCRIPT_OBJECT 0 /* has (new Script("x++")).exec() */
+#define JS_HAS_XDR 0 /* has XDR API and internal support */
+#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */
+#define JS_HAS_EXCEPTIONS 0 /* has exception handling */
+#define JS_HAS_UNDEFINED 0 /* has global "undefined" property */
+#define JS_HAS_TOSOURCE 0 /* has Object/Array toSource method */
+#define JS_HAS_IN_OPERATOR 0 /* has in operator ('p' in {p:1}) */
+#define JS_HAS_INSTANCEOF 0 /* has {p:1} instanceof Object */
+#define JS_HAS_ARGS_OBJECT 0 /* has minimal ECMA arguments object */
+#define JS_HAS_DEBUGGER_KEYWORD 0 /* has hook for debugger keyword */
+#define JS_HAS_ERROR_EXCEPTIONS 0 /* has error object hierarchy */
+#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
+#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
+#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
+#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
+#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
+#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
+#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */
+#define JS_HAS_CONST 0 /* has JS2 const as alternative var */
+#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */
+#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
+#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
+
+#elif JS_VERSION == 120
+
+#define JS_BUG_NULL_INDEX_PROPS 0 /* o[0] defaults to null, not void */
+#define JS_BUG_EMPTY_INDEX_ZERO 0 /* o[""] is equivalent to o[0] */
+#define JS_BUG_EAGER_TOSTRING 0 /* o.toString() trumps o.valueOf() */
+#define JS_BUG_VOID_TOSTRING 1 /* void 0 + 0 == "undefined0" */
+#define JS_BUG_EVAL_THIS_FUN 0 /* eval('this') in function f is f */
+#define JS_BUG_EVAL_THIS_SCOPE 0 /* Math.eval('sin(x)') vs. local x */
+#define JS_BUG_FALLIBLE_EQOPS 0 /* fallible/intransitive equality ops */
+#define JS_BUG_FALLIBLE_TONUM 0 /* fallible ValueToNumber primitive */
+#define JS_BUG_WITH_CLOSURE 1 /* with(o)function f(){} sets o.f */
+
+#define JS_HAS_PROP_DELETE 1 /* delete o.p removes p from o */
+#define JS_HAS_CALL_OBJECT 1 /* fun.caller is stack frame obj */
+#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */
+#define JS_HAS_DO_WHILE_LOOP 1 /* has do {...} while (b) */
+#define JS_HAS_SWITCH_STATEMENT 1 /* has switch (v) {case c: ...} */
+#define JS_HAS_SOME_PERL_FUN 1 /* has array.join/reverse/sort */
+#define JS_HAS_MORE_PERL_FUN 1 /* has array.push, str.substr, etc */
+#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
+#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */
+#define JS_HAS_VALUEOF_HINT 1 /* valueOf(hint) where hint is typeof */
+#define JS_HAS_LEXICAL_CLOSURE 1 /* nested functions, lexically closed */
+#define JS_HAS_APPLY_FUNCTION 1 /* has apply(fun, arg1, ... argN) */
+#define JS_HAS_CALL_FUNCTION 0 /* has fun.call(obj, arg1, ... argN) */
+#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
+#define JS_HAS_REGEXPS 1 /* has perl r.e.s via RegExp, /pat/ */
+#define JS_HAS_SEQUENCE_OPS 1 /* has array.slice, string.concat */
+#define JS_HAS_INITIALIZERS 1 /* has var o = {'foo': 42, 'bar':3} */
+#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
+#define JS_HAS_EXPORT_IMPORT 1 /* has export fun; import obj.fun */
+#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */
+#define JS_HAS_TRIPLE_EQOPS 0 /* has === and !== identity eqops */
+#define JS_HAS_SHARP_VARS 0 /* has #n=, #n# for object literals */
+#define JS_HAS_REPLACE_LAMBDA 0 /* has string.replace(re, lambda) */
+#define JS_HAS_SCRIPT_OBJECT 0 /* has (new Script("x++")).exec() */
+#define JS_HAS_XDR 0 /* has XDR API and internal support */
+#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */
+#define JS_HAS_EXCEPTIONS 0 /* has exception handling */
+#define JS_HAS_UNDEFINED 0 /* has global "undefined" property */
+#define JS_HAS_TOSOURCE 0 /* has Object/Array toSource method */
+#define JS_HAS_IN_OPERATOR 0 /* has in operator ('p' in {p:1}) */
+#define JS_HAS_INSTANCEOF 0 /* has {p:1} instanceof Object */
+#define JS_HAS_ARGS_OBJECT 0 /* has minimal ECMA arguments object */
+#define JS_HAS_DEBUGGER_KEYWORD 0 /* has hook for debugger keyword */
+#define JS_HAS_ERROR_EXCEPTIONS 0 /* has error object hierarchy */
+#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
+#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
+#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
+#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
+#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
+#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
+#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */
+#define JS_HAS_CONST 0 /* has JS2 const as alternative var */
+#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */
+#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
+#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
+
+#elif JS_VERSION == 130
+
+#define JS_BUG_NULL_INDEX_PROPS 0 /* o[0] defaults to null, not void */
+#define JS_BUG_EMPTY_INDEX_ZERO 0 /* o[""] is equivalent to o[0] */
+#define JS_BUG_EAGER_TOSTRING 0 /* o.toString() trumps o.valueOf() */
+#define JS_BUG_VOID_TOSTRING 0 /* void 0 + 0 == "undefined0" */
+#define JS_BUG_EVAL_THIS_FUN 0 /* eval('this') in function f is f */
+#define JS_BUG_EVAL_THIS_SCOPE 0 /* Math.eval('sin(x)') vs. local x */
+#define JS_BUG_FALLIBLE_EQOPS 0 /* fallible/intransitive equality ops */
+#define JS_BUG_FALLIBLE_TONUM 0 /* fallible ValueToNumber primitive */
+#define JS_BUG_WITH_CLOSURE 1 /* with(o)function f(){} sets o.f */
+
+#define JS_HAS_PROP_DELETE 1 /* delete o.p removes p from o */
+#define JS_HAS_CALL_OBJECT 1 /* fun.caller is stack frame obj */
+#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */
+#define JS_HAS_DO_WHILE_LOOP 1 /* has do {...} while (b) */
+#define JS_HAS_SWITCH_STATEMENT 1 /* has switch (v) {case c: ...} */
+#define JS_HAS_SOME_PERL_FUN 1 /* has array.join/reverse/sort */
+#define JS_HAS_MORE_PERL_FUN 1 /* has array.push, str.substr, etc */
+#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
+#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */
+#define JS_HAS_VALUEOF_HINT 1 /* valueOf(hint) where hint is typeof */
+#define JS_HAS_LEXICAL_CLOSURE 1 /* nested functions, lexically closed */
+#define JS_HAS_APPLY_FUNCTION 1 /* has apply(fun, arg1, ... argN) */
+#define JS_HAS_CALL_FUNCTION 1 /* has fun.call(obj, arg1, ... argN) */
+#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
+#define JS_HAS_REGEXPS 1 /* has perl r.e.s via RegExp, /pat/ */
+#define JS_HAS_SEQUENCE_OPS 1 /* has array.slice, string.concat */
+#define JS_HAS_INITIALIZERS 1 /* has var o = {'foo': 42, 'bar':3} */
+#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
+#define JS_HAS_EXPORT_IMPORT 1 /* has export fun; import obj.fun */
+#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */
+#define JS_HAS_TRIPLE_EQOPS 1 /* has === and !== identity eqops */
+#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */
+#define JS_HAS_REPLACE_LAMBDA 1 /* has string.replace(re, lambda) */
+#define JS_HAS_SCRIPT_OBJECT 1 /* has (new Script("x++")).exec() */
+#define JS_HAS_XDR 1 /* has XDR API and internal support */
+#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */
+#define JS_HAS_EXCEPTIONS 0 /* has exception handling */
+#define JS_HAS_UNDEFINED 1 /* has global "undefined" property */
+#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
+#define JS_HAS_IN_OPERATOR 0 /* has in operator ('p' in {p:1}) */
+#define JS_HAS_INSTANCEOF 0 /* has {p:1} instanceof Object */
+#define JS_HAS_ARGS_OBJECT 1 /* has minimal ECMA arguments object */
+#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */
+#define JS_HAS_ERROR_EXCEPTIONS 0 /* has error object hierarchy */
+#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
+#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
+#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
+#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
+#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
+#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
+#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */
+#define JS_HAS_CONST 0 /* has JS2 const as alternative var */
+#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */
+#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
+#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
+
+#elif JS_VERSION == 140
+
+#define JS_BUG_NULL_INDEX_PROPS 0 /* o[0] defaults to null, not void */
+#define JS_BUG_EMPTY_INDEX_ZERO 0 /* o[""] is equivalent to o[0] */
+#define JS_BUG_EAGER_TOSTRING 0 /* o.toString() trumps o.valueOf() */
+#define JS_BUG_VOID_TOSTRING 0 /* void 0 + 0 == "undefined0" */
+#define JS_BUG_EVAL_THIS_FUN 0 /* eval('this') in function f is f */
+#define JS_BUG_EVAL_THIS_SCOPE 0 /* Math.eval('sin(x)') vs. local x */
+#define JS_BUG_FALLIBLE_EQOPS 0 /* fallible/intransitive equality ops */
+#define JS_BUG_FALLIBLE_TONUM 0 /* fallible ValueToNumber primitive */
+#define JS_BUG_WITH_CLOSURE 1 /* with(o)function f(){} sets o.f */
+
+#define JS_HAS_PROP_DELETE 1 /* delete o.p removes p from o */
+#define JS_HAS_CALL_OBJECT 1 /* fun.caller is stack frame obj */
+#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */
+#define JS_HAS_DO_WHILE_LOOP 1 /* has do {...} while (b) */
+#define JS_HAS_SWITCH_STATEMENT 1 /* has switch (v) {case c: ...} */
+#define JS_HAS_SOME_PERL_FUN 1 /* has array.join/reverse/sort */
+#define JS_HAS_MORE_PERL_FUN 1 /* has array.push, str.substr, etc */
+#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
+#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */
+#define JS_HAS_VALUEOF_HINT 1 /* valueOf(hint) where hint is typeof */
+#define JS_HAS_LEXICAL_CLOSURE 1 /* nested functions, lexically closed */
+#define JS_HAS_APPLY_FUNCTION 1 /* has apply(fun, arg1, ... argN) */
+#define JS_HAS_CALL_FUNCTION 1 /* has fun.call(obj, arg1, ... argN) */
+#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
+#define JS_HAS_REGEXPS 1 /* has perl r.e.s via RegExp, /pat/ */
+#define JS_HAS_SEQUENCE_OPS 1 /* has array.slice, string.concat */
+#define JS_HAS_INITIALIZERS 1 /* has var o = {'foo': 42, 'bar':3} */
+#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
+#define JS_HAS_EXPORT_IMPORT 1 /* has export fun; import obj.fun */
+#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */
+#define JS_HAS_TRIPLE_EQOPS 1 /* has === and !== identity eqops */
+#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */
+#define JS_HAS_REPLACE_LAMBDA 1 /* has string.replace(re, lambda) */
+#define JS_HAS_SCRIPT_OBJECT 1 /* has (new Script("x++")).exec() */
+#define JS_HAS_XDR 1 /* has XDR API and internal support */
+#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */
+#define JS_HAS_EXCEPTIONS 1 /* has exception handling */
+#define JS_HAS_UNDEFINED 1 /* has global "undefined" property */
+#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
+#define JS_HAS_IN_OPERATOR 1 /* has in operator ('p' in {p:1}) */
+#define JS_HAS_INSTANCEOF 1 /* has {p:1} instanceof Object */
+#define JS_HAS_ARGS_OBJECT 1 /* has minimal ECMA arguments object */
+#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */
+#define JS_HAS_ERROR_EXCEPTIONS 0 /* rt errors reflected as exceptions */
+#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
+#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
+#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
+#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
+#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
+#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
+#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */
+#define JS_HAS_CONST 0 /* has JS2 const as alternative var */
+#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */
+#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
+#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
+
+#elif JS_VERSION == 150
+
+#define JS_BUG_NULL_INDEX_PROPS 0 /* o[0] defaults to null, not void */
+#define JS_BUG_EMPTY_INDEX_ZERO 0 /* o[""] is equivalent to o[0] */
+#define JS_BUG_EAGER_TOSTRING 0 /* o.toString() trumps o.valueOf() */
+#define JS_BUG_VOID_TOSTRING 0 /* void 0 + 0 == "undefined0" */
+#define JS_BUG_EVAL_THIS_FUN 0 /* eval('this') in function f is f */
+#define JS_BUG_EVAL_THIS_SCOPE 0 /* Math.eval('sin(x)') vs. local x */
+#define JS_BUG_FALLIBLE_EQOPS 0 /* fallible/intransitive equality ops */
+#define JS_BUG_FALLIBLE_TONUM 0 /* fallible ValueToNumber primitive */
+#define JS_BUG_WITH_CLOSURE 0 /* with(o)function f(){} sets o.f */
+
+#define JS_HAS_PROP_DELETE 1 /* delete o.p removes p from o */
+#define JS_HAS_CALL_OBJECT 1 /* fun.caller is stack frame obj */
+#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */
+#define JS_HAS_DO_WHILE_LOOP 1 /* has do {...} while (b) */
+#define JS_HAS_SWITCH_STATEMENT 1 /* has switch (v) {case c: ...} */
+#define JS_HAS_SOME_PERL_FUN 1 /* has array.join/reverse/sort */
+#define JS_HAS_MORE_PERL_FUN 1 /* has array.push, str.substr, etc */
+#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
+#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */
+#define JS_HAS_VALUEOF_HINT 1 /* valueOf(hint) where hint is typeof */
+#define JS_HAS_LEXICAL_CLOSURE 1 /* nested functions, lexically closed */
+#define JS_HAS_APPLY_FUNCTION 1 /* has apply(fun, arg1, ... argN) */
+#define JS_HAS_CALL_FUNCTION 1 /* has fun.call(obj, arg1, ... argN) */
+#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
+#define JS_HAS_REGEXPS 1 /* has perl r.e.s via RegExp, /pat/ */
+#define JS_HAS_SEQUENCE_OPS 1 /* has array.slice, string.concat */
+#define JS_HAS_INITIALIZERS 1 /* has var o = {'foo': 42, 'bar':3} */
+#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
+#define JS_HAS_EXPORT_IMPORT 0 /* has export fun; import obj.fun */
+#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */
+#define JS_HAS_TRIPLE_EQOPS 1 /* has === and !== identity eqops */
+#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */
+#define JS_HAS_REPLACE_LAMBDA 1 /* has string.replace(re, lambda) */
+#define JS_HAS_SCRIPT_OBJECT 1 /* has (new Script("x++")).exec() */
+#define JS_HAS_XDR 1 /* has XDR API and internal support */
+#define JS_HAS_XDR_FREEZE_THAW 0 /* has XDR freeze/thaw script methods */
+#define JS_HAS_EXCEPTIONS 1 /* has exception handling */
+#define JS_HAS_UNDEFINED 1 /* has global "undefined" property */
+#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
+#define JS_HAS_IN_OPERATOR 1 /* has in operator ('p' in {p:1}) */
+#define JS_HAS_INSTANCEOF 1 /* has {p:1} instanceof Object */
+#define JS_HAS_ARGS_OBJECT 1 /* has minimal ECMA arguments object */
+#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */
+#define JS_HAS_ERROR_EXCEPTIONS 1 /* rt errors reflected as exceptions */
+#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */
+#define JS_HAS_NEW_OBJ_METHODS 1 /* has Object.prototype query methods */
+#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
+#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
+#define JS_HAS_NUMBER_FORMATS 1 /* numbers have formatting methods */
+#define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */
+#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */
+#define JS_HAS_CONST 1 /* has JS2 const as alternative var */
+#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */
+#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */
+#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */
+
+#else
+
+#error "unknown JS_VERSION"
+
+#endif
diff --git a/src/dom/js/jscpucfg.c b/src/dom/js/jscpucfg.c
new file mode 100644
index 000000000..aa6c04c4d
--- /dev/null
+++ b/src/dom/js/jscpucfg.c
@@ -0,0 +1,377 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Generate CPU-specific bit-size and similar #defines.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef CROSS_COMPILE
+#include <prtypes.h>
+#define INT64 PRInt64
+#else
+
+#ifdef __MWERKS__
+#define XP_MAC 1
+#endif
+
+/************************************************************************/
+
+/* Generate cpucfg.h */
+#ifdef XP_MAC
+#include <Types.h>
+#define INT64 UnsignedWide
+#else
+#if defined(XP_WIN) || defined(XP_OS2)
+#ifdef WIN32
+#if defined(__GNUC__)
+#define INT64 long long
+#else
+#define INT64 _int64
+#endif /* __GNUC__ */
+#else
+#define INT64 long
+#endif
+#else
+#if defined(HPUX) || defined(__QNX__) || defined(_SCO_DS) || defined(UNIXWARE)
+#define INT64 long
+#else
+#define INT64 long long
+#endif
+#endif
+#endif
+
+#endif /* CROSS_COMPILE */
+
+typedef void *prword;
+
+struct align_short {
+ char c;
+ short a;
+};
+struct align_int {
+ char c;
+ int a;
+};
+struct align_long {
+ char c;
+ long a;
+};
+struct align_int64 {
+ char c;
+ INT64 a;
+};
+struct align_fakelonglong {
+ char c;
+ struct {
+ long hi, lo;
+ } a;
+};
+struct align_float {
+ char c;
+ float a;
+};
+struct align_double {
+ char c;
+ double a;
+};
+struct align_pointer {
+ char c;
+ void *a;
+};
+struct align_prword {
+ char c;
+ prword a;
+};
+
+#define ALIGN_OF(type) \
+ (((char*)&(((struct align_##type *)0)->a)) - ((char*)0))
+
+unsigned int bpb;
+
+static int Log2(unsigned int n)
+{
+ int log2 = 0;
+
+ if (n & (n-1))
+ log2++;
+ if (n >> 16)
+ log2 += 16, n >>= 16;
+ if (n >> 8)
+ log2 += 8, n >>= 8;
+ if (n >> 4)
+ log2 += 4, n >>= 4;
+ if (n >> 2)
+ log2 += 2, n >>= 2;
+ if (n >> 1)
+ log2++;
+ return log2;
+}
+
+/*
+ * Conceivably this could actually be used, but there is lots of code out
+ * there with ands and shifts in it that assumes a byte is exactly 8 bits,
+ * so forget about porting THIS code to all those non 8 bit byte machines.
+ */
+static void BitsPerByte(void)
+{
+ bpb = 8;
+}
+
+static int StackGrowthDirection(int *dummy1addr)
+{
+ int dummy2;
+
+ return (&dummy2 < dummy1addr) ? -1 : 1;
+}
+
+int main(int argc, char **argv)
+{
+ int sizeof_char, sizeof_short, sizeof_int, sizeof_int64, sizeof_long,
+ sizeof_float, sizeof_double, sizeof_word, sizeof_dword;
+ int bits_per_int64_log2, align_of_short, align_of_int, align_of_long,
+ align_of_int64, align_of_float, align_of_double, align_of_pointer,
+ align_of_word;
+ int dummy1;
+
+ BitsPerByte();
+
+ printf("#ifndef js_cpucfg___\n");
+ printf("#define js_cpucfg___\n\n");
+
+ printf("/* AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n");
+
+#ifdef CROSS_COMPILE
+#if defined(IS_LITTLE_ENDIAN)
+ printf("#define IS_LITTLE_ENDIAN 1\n");
+ printf("#undef IS_BIG_ENDIAN\n\n");
+#elif defined(IS_BIG_ENDIAN)
+ printf("#undef IS_LITTLE_ENDIAN\n");
+ printf("#define IS_BIG_ENDIAN 1\n\n");
+#else
+#error "Endianess not defined."
+#endif
+
+ sizeof_char = PR_BYTES_PER_BYTE;
+ sizeof_short = PR_BYTES_PER_SHORT;
+ sizeof_int = PR_BYTES_PER_INT;
+ sizeof_int64 = PR_BYTES_PER_INT64;
+ sizeof_long = PR_BYTES_PER_LONG;
+ sizeof_float = PR_BYTES_PER_FLOAT;
+ sizeof_double = PR_BYTES_PER_DOUBLE;
+ sizeof_word = PR_BYTES_PER_WORD;
+ sizeof_dword = PR_BYTES_PER_DWORD;
+
+ bits_per_int64_log2 = PR_BITS_PER_INT64_LOG2;
+
+ align_of_short = PR_ALIGN_OF_SHORT;
+ align_of_int = PR_ALIGN_OF_INT;
+ align_of_long = PR_ALIGN_OF_LONG;
+ align_of_int64 = PR_ALIGN_OF_INT64;
+ align_of_float = PR_ALIGN_OF_FLOAT;
+ align_of_double = PR_ALIGN_OF_DOUBLE;
+ align_of_pointer = PR_ALIGN_OF_POINTER;
+ align_of_word = PR_ALIGN_OF_WORD;
+
+#else /* !CROSS_COMPILE */
+
+ /*
+ * We don't handle PDP-endian or similar orders: if a short is big-endian,
+ * so must int and long be big-endian for us to generate the IS_BIG_ENDIAN
+ * #define and the IS_LITTLE_ENDIAN #undef.
+ */
+ {
+ int big_endian = 0, little_endian = 0, ntests = 0;
+
+ if (sizeof(short) == 2) {
+ /* force |volatile| here to get rid of any compiler optimisations
+ * (var in register etc.) which may be appiled to |auto| vars -
+ * even those in |union|s...
+ * (|static| is used to get the same functionality for compilers
+ * which do not honor |volatile|...).
+ */
+ volatile static union {
+ short i;
+ char c[2];
+ } u;
+
+ u.i = 0x0102;
+ big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02);
+ little_endian += (u.c[0] == 0x02 && u.c[1] == 0x01);
+ ntests++;
+ }
+
+ if (sizeof(int) == 4) {
+ /* force |volatile| here ... */
+ volatile static union {
+ int i;
+ char c[4];
+ } u;
+
+ u.i = 0x01020304;
+ big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 &&
+ u.c[2] == 0x03 && u.c[3] == 0x04);
+ little_endian += (u.c[0] == 0x04 && u.c[1] == 0x03 &&
+ u.c[2] == 0x02 && u.c[3] == 0x01);
+ ntests++;
+ }
+
+ if (sizeof(long) == 8) {
+ /* force |volatile| here ... */
+ volatile static union {
+ long i;
+ char c[8];
+ } u;
+
+ /*
+ * Write this as portably as possible: avoid 0x0102030405060708L
+ * and <<= 32.
+ */
+ u.i = 0x01020304;
+ u.i <<= 16, u.i <<= 16;
+ u.i |= 0x05060708;
+ big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 &&
+ u.c[2] == 0x03 && u.c[3] == 0x04 &&
+ u.c[4] == 0x05 && u.c[5] == 0x06 &&
+ u.c[6] == 0x07 && u.c[7] == 0x08);
+ little_endian += (u.c[0] == 0x08 && u.c[1] == 0x07 &&
+ u.c[2] == 0x06 && u.c[3] == 0x05 &&
+ u.c[4] == 0x04 && u.c[5] == 0x03 &&
+ u.c[6] == 0x02 && u.c[7] == 0x01);
+ ntests++;
+ }
+
+ if (big_endian && big_endian == ntests) {
+ printf("#undef IS_LITTLE_ENDIAN\n");
+ printf("#define IS_BIG_ENDIAN 1\n\n");
+ } else if (little_endian && little_endian == ntests) {
+ printf("#define IS_LITTLE_ENDIAN 1\n");
+ printf("#undef IS_BIG_ENDIAN\n\n");
+ } else {
+ fprintf(stderr, "%s: unknown byte order"
+ "(big_endian=%d, little_endian=%d, ntests=%d)!\n",
+ argv[0], big_endian, little_endian, ntests);
+ return EXIT_FAILURE;
+ }
+ }
+
+ sizeof_char = sizeof(char);
+ sizeof_short = sizeof(short);
+ sizeof_int = sizeof(int);
+ sizeof_int64 = 8;
+ sizeof_long = sizeof(long);
+ sizeof_float = sizeof(float);
+ sizeof_double = sizeof(double);
+ sizeof_word = sizeof(prword);
+ sizeof_dword = 8;
+
+ bits_per_int64_log2 = 6;
+
+ align_of_short = ALIGN_OF(short);
+ align_of_int = ALIGN_OF(int);
+ align_of_long = ALIGN_OF(long);
+ if (sizeof(INT64) < 8) {
+ /* this machine doesn't actually support int64's */
+ align_of_int64 = ALIGN_OF(fakelonglong);
+ } else {
+ align_of_int64 = ALIGN_OF(int64);
+ }
+ align_of_float = ALIGN_OF(float);
+ align_of_double = ALIGN_OF(double);
+ align_of_pointer = ALIGN_OF(pointer);
+ align_of_word = ALIGN_OF(prword);
+
+#endif /* CROSS_COMPILE */
+
+ printf("#define JS_BYTES_PER_BYTE %dL\n", sizeof_char);
+ printf("#define JS_BYTES_PER_SHORT %dL\n", sizeof_short);
+ printf("#define JS_BYTES_PER_INT %dL\n", sizeof_int);
+ printf("#define JS_BYTES_PER_INT64 %dL\n", sizeof_int64);
+ printf("#define JS_BYTES_PER_LONG %dL\n", sizeof_long);
+ printf("#define JS_BYTES_PER_FLOAT %dL\n", sizeof_float);
+ printf("#define JS_BYTES_PER_DOUBLE %dL\n", sizeof_double);
+ printf("#define JS_BYTES_PER_WORD %dL\n", sizeof_word);
+ printf("#define JS_BYTES_PER_DWORD %dL\n", sizeof_dword);
+ printf("\n");
+
+ printf("#define JS_BITS_PER_BYTE %dL\n", bpb);
+ printf("#define JS_BITS_PER_SHORT %dL\n", bpb * sizeof_short);
+ printf("#define JS_BITS_PER_INT %dL\n", bpb * sizeof_int);
+ printf("#define JS_BITS_PER_INT64 %dL\n", bpb * sizeof_int64);
+ printf("#define JS_BITS_PER_LONG %dL\n", bpb * sizeof_long);
+ printf("#define JS_BITS_PER_FLOAT %dL\n", bpb * sizeof_float);
+ printf("#define JS_BITS_PER_DOUBLE %dL\n", bpb * sizeof_double);
+ printf("#define JS_BITS_PER_WORD %dL\n", bpb * sizeof_word);
+ printf("\n");
+
+ printf("#define JS_BITS_PER_BYTE_LOG2 %dL\n", Log2(bpb));
+ printf("#define JS_BITS_PER_SHORT_LOG2 %dL\n", Log2(bpb * sizeof_short));
+ printf("#define JS_BITS_PER_INT_LOG2 %dL\n", Log2(bpb * sizeof_int));
+ printf("#define JS_BITS_PER_INT64_LOG2 %dL\n", bits_per_int64_log2);
+ printf("#define JS_BITS_PER_LONG_LOG2 %dL\n", Log2(bpb * sizeof_long));
+ printf("#define JS_BITS_PER_FLOAT_LOG2 %dL\n", Log2(bpb * sizeof_float));
+ printf("#define JS_BITS_PER_DOUBLE_LOG2 %dL\n", Log2(bpb * sizeof_double));
+ printf("#define JS_BITS_PER_WORD_LOG2 %dL\n", Log2(bpb * sizeof_word));
+ printf("\n");
+
+ printf("#define JS_ALIGN_OF_SHORT %dL\n", align_of_short);
+ printf("#define JS_ALIGN_OF_INT %dL\n", align_of_int);
+ printf("#define JS_ALIGN_OF_LONG %dL\n", align_of_long);
+ printf("#define JS_ALIGN_OF_INT64 %dL\n", align_of_int64);
+ printf("#define JS_ALIGN_OF_FLOAT %dL\n", align_of_float);
+ printf("#define JS_ALIGN_OF_DOUBLE %dL\n", align_of_double);
+ printf("#define JS_ALIGN_OF_POINTER %dL\n", align_of_pointer);
+ printf("#define JS_ALIGN_OF_WORD %dL\n", align_of_word);
+ printf("\n");
+
+ printf("#define JS_BYTES_PER_WORD_LOG2 %dL\n", Log2(sizeof_word));
+ printf("#define JS_BYTES_PER_DWORD_LOG2 %dL\n", Log2(sizeof_dword));
+ printf("#define JS_WORDS_PER_DWORD_LOG2 %dL\n", Log2(sizeof_dword/sizeof_word));
+ printf("\n");
+
+ printf("#define JS_STACK_GROWTH_DIRECTION (%d)\n", StackGrowthDirection(&dummy1));
+ printf("\n");
+
+ printf("#endif /* js_cpucfg___ */\n");
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/src/dom/js/jscpucfg.h b/src/dom/js/jscpucfg.h
new file mode 100644
index 000000000..e93f5531d
--- /dev/null
+++ b/src/dom/js/jscpucfg.h
@@ -0,0 +1,200 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef js_cpucfg___
+#define js_cpucfg___
+
+#include "jsosdep.h"
+
+#ifdef XP_MAC
+#undef IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+
+#define JS_BYTES_PER_BYTE 1L
+#define JS_BYTES_PER_SHORT 2L
+#define JS_BYTES_PER_INT 4L
+#define JS_BYTES_PER_INT64 8L
+#define JS_BYTES_PER_LONG 4L
+#define JS_BYTES_PER_FLOAT 4L
+#define JS_BYTES_PER_DOUBLE 8L
+#define JS_BYTES_PER_WORD 4L
+#define JS_BYTES_PER_DWORD 8L
+
+#define JS_BITS_PER_BYTE 8L
+#define JS_BITS_PER_SHORT 16L
+#define JS_BITS_PER_INT 32L
+#define JS_BITS_PER_INT64 64L
+#define JS_BITS_PER_LONG 32L
+#define JS_BITS_PER_FLOAT 32L
+#define JS_BITS_PER_DOUBLE 64L
+#define JS_BITS_PER_WORD 32L
+
+#define JS_BITS_PER_BYTE_LOG2 3L
+#define JS_BITS_PER_SHORT_LOG2 4L
+#define JS_BITS_PER_INT_LOG2 5L
+#define JS_BITS_PER_INT64_LOG2 6L
+#define JS_BITS_PER_LONG_LOG2 5L
+#define JS_BITS_PER_FLOAT_LOG2 5L
+#define JS_BITS_PER_DOUBLE_LOG2 6L
+#define JS_BITS_PER_WORD_LOG2 5L
+
+#define JS_ALIGN_OF_SHORT 2L
+#define JS_ALIGN_OF_INT 4L
+#define JS_ALIGN_OF_LONG 4L
+#define JS_ALIGN_OF_INT64 2L
+#define JS_ALIGN_OF_FLOAT 4L
+#define JS_ALIGN_OF_DOUBLE 4L
+#define JS_ALIGN_OF_POINTER 4L
+#define JS_ALIGN_OF_WORD 4L
+
+#define JS_BYTES_PER_WORD_LOG2 2L
+#define JS_BYTES_PER_DWORD_LOG2 3L
+#define PR_WORDS_PER_DWORD_LOG2 1L
+
+#elif defined(XP_WIN) || defined(XP_OS2)
+
+#if defined( _WIN32) || defined(XP_OS2)
+#define IS_LITTLE_ENDIAN 1
+#undef IS_BIG_ENDIAN
+
+#define JS_BYTES_PER_BYTE 1L
+#define JS_BYTES_PER_SHORT 2L
+#define JS_BYTES_PER_INT 4L
+#define JS_BYTES_PER_INT64 8L
+#define JS_BYTES_PER_LONG 4L
+#define JS_BYTES_PER_FLOAT 4L
+#define JS_BYTES_PER_DOUBLE 8L
+#define JS_BYTES_PER_WORD 4L
+#define JS_BYTES_PER_DWORD 8L
+
+#define JS_BITS_PER_BYTE 8L
+#define JS_BITS_PER_SHORT 16L
+#define JS_BITS_PER_INT 32L
+#define JS_BITS_PER_INT64 64L
+#define JS_BITS_PER_LONG 32L
+#define JS_BITS_PER_FLOAT 32L
+#define JS_BITS_PER_DOUBLE 64L
+#define JS_BITS_PER_WORD 32L
+
+#define JS_BITS_PER_BYTE_LOG2 3L
+#define JS_BITS_PER_SHORT_LOG2 4L
+#define JS_BITS_PER_INT_LOG2 5L
+#define JS_BITS_PER_INT64_LOG2 6L
+#define JS_BITS_PER_LONG_LOG2 5L
+#define JS_BITS_PER_FLOAT_LOG2 5L
+#define JS_BITS_PER_DOUBLE_LOG2 6L
+#define JS_BITS_PER_WORD_LOG2 5L
+
+#define JS_ALIGN_OF_SHORT 2L
+#define JS_ALIGN_OF_INT 4L
+#define JS_ALIGN_OF_LONG 4L
+#define JS_ALIGN_OF_INT64 8L
+#define JS_ALIGN_OF_FLOAT 4L
+#define JS_ALIGN_OF_DOUBLE 4L
+#define JS_ALIGN_OF_POINTER 4L
+#define JS_ALIGN_OF_WORD 4L
+
+#define JS_BYTES_PER_WORD_LOG2 2L
+#define JS_BYTES_PER_DWORD_LOG2 3L
+#define PR_WORDS_PER_DWORD_LOG2 1L
+#endif /* _WIN32 || XP_OS2 */
+
+#if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */
+#define IS_LITTLE_ENDIAN 1
+#undef IS_BIG_ENDIAN
+
+#define JS_BYTES_PER_BYTE 1L
+#define JS_BYTES_PER_SHORT 2L
+#define JS_BYTES_PER_INT 2L
+#define JS_BYTES_PER_INT64 8L
+#define JS_BYTES_PER_LONG 4L
+#define JS_BYTES_PER_FLOAT 4L
+#define JS_BYTES_PER_DOUBLE 8L
+#define JS_BYTES_PER_WORD 4L
+#define JS_BYTES_PER_DWORD 8L
+
+#define JS_BITS_PER_BYTE 8L
+#define JS_BITS_PER_SHORT 16L
+#define JS_BITS_PER_INT 16L
+#define JS_BITS_PER_INT64 64L
+#define JS_BITS_PER_LONG 32L
+#define JS_BITS_PER_FLOAT 32L
+#define JS_BITS_PER_DOUBLE 64L
+#define JS_BITS_PER_WORD 32L
+
+#define JS_BITS_PER_BYTE_LOG2 3L
+#define JS_BITS_PER_SHORT_LOG2 4L
+#define JS_BITS_PER_INT_LOG2 4L
+#define JS_BITS_PER_INT64_LOG2 6L
+#define JS_BITS_PER_LONG_LOG2 5L
+#define JS_BITS_PER_FLOAT_LOG2 5L
+#define JS_BITS_PER_DOUBLE_LOG2 6L
+#define JS_BITS_PER_WORD_LOG2 5L
+
+#define JS_ALIGN_OF_SHORT 2L
+#define JS_ALIGN_OF_INT 2L
+#define JS_ALIGN_OF_LONG 2L
+#define JS_ALIGN_OF_INT64 2L
+#define JS_ALIGN_OF_FLOAT 2L
+#define JS_ALIGN_OF_DOUBLE 2L
+#define JS_ALIGN_OF_POINTER 2L
+#define JS_ALIGN_OF_WORD 2L
+
+#define JS_BYTES_PER_WORD_LOG2 2L
+#define JS_BYTES_PER_DWORD_LOG2 3L
+#define PR_WORDS_PER_DWORD_LOG2 1L
+#endif /* defined(_WINDOWS) && !defined(_WIN32) */
+
+#elif defined(XP_UNIX) || defined(XP_BEOS)
+
+#error "This file is supposed to be auto-generated on UNIX platforms, but the"
+#error "static version for Mac and Windows platforms is being used."
+#error "Something's probably wrong with paths/headers/dependencies/Makefiles."
+
+#else
+
+#error "Must define one of XP_BEOS, XP_MAC, XP_OS2, XP_WIN, or XP_UNIX"
+
+#endif
+
+#ifndef JS_STACK_GROWTH_DIRECTION
+#define JS_STACK_GROWTH_DIRECTION (-1)
+#endif
+
+#endif /* js_cpucfg___ */
diff --git a/src/dom/js/jsdate.c b/src/dom/js/jsdate.c
new file mode 100644
index 000000000..a88df1830
--- /dev/null
+++ b/src/dom/js/jsdate.c
@@ -0,0 +1,2234 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS date methods.
+ */
+
+/*
+ * "For example, OS/360 devotes 26 bytes of the permanently
+ * resident date-turnover routine to the proper handling of
+ * December 31 on leap years (when it is Day 366). That
+ * might have been left to the operator."
+ *
+ * Frederick Brooks, 'The Second-System Effect'.
+ */
+
+#include "jsstddef.h"
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsprf.h"
+#include "prmjtime.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsconfig.h"
+#include "jscntxt.h"
+#include "jsdate.h"
+#include "jsinterp.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsstr.h"
+
+/*
+ * The JS 'Date' object is patterned after the Java 'Date' object.
+ * Here is an script:
+ *
+ * today = new Date();
+ *
+ * print(today.toLocaleString());
+ *
+ * weekDay = today.getDay();
+ *
+ *
+ * These Java (and ECMA-262) methods are supported:
+ *
+ * UTC
+ * getDate (getUTCDate)
+ * getDay (getUTCDay)
+ * getHours (getUTCHours)
+ * getMinutes (getUTCMinutes)
+ * getMonth (getUTCMonth)
+ * getSeconds (getUTCSeconds)
+ * getMilliseconds (getUTCMilliseconds)
+ * getTime
+ * getTimezoneOffset
+ * getYear
+ * getFullYear (getUTCFullYear)
+ * parse
+ * setDate (setUTCDate)
+ * setHours (setUTCHours)
+ * setMinutes (setUTCMinutes)
+ * setMonth (setUTCMonth)
+ * setSeconds (setUTCSeconds)
+ * setMilliseconds (setUTCMilliseconds)
+ * setTime
+ * setYear (setFullYear, setUTCFullYear)
+ * toGMTString (toUTCString)
+ * toLocaleString
+ * toString
+ *
+ *
+ * These Java methods are not supported
+ *
+ * setDay
+ * before
+ * after
+ * equals
+ * hashCode
+ */
+
+/*
+ * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
+ * definition and reduce dependence on NSPR. NSPR is used to get the current
+ * time in milliseconds, the time zone offset, and the daylight savings time
+ * offset for a given time. NSPR is also used for Date.toLocaleString(), for
+ * locale-specific formatting, and to get a string representing the timezone.
+ * (Which turns out to be platform-dependent.)
+ *
+ * To do:
+ * (I did some performance tests by timing how long it took to run what
+ * I had of the js ECMA conformance tests.)
+ *
+ * - look at saving results across multiple calls to supporting
+ * functions; the toString functions compute some of the same values
+ * multiple times. Although - I took a quick stab at this, and I lost
+ * rather than gained. (Fractionally.) Hard to tell what compilers/processors
+ * are doing these days.
+ *
+ * - look at tweaking function return types to return double instead
+ * of int; this seems to make things run slightly faster sometimes.
+ * (though it could be architecture-dependent.) It'd be good to see
+ * how this does on win32. (Tried it on irix.) Types could use a
+ * general going-over.
+ */
+
+/*
+ * Supporting functions - ECMA 15.9.1.*
+ */
+
+#define HalfTimeDomain 8.64e15
+#define HoursPerDay 24.0
+#define MinutesPerDay (HoursPerDay * MinutesPerHour)
+#define MinutesPerHour 60.0
+#define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
+#define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
+#define SecondsPerMinute 60.0
+
+#if defined(XP_WIN) || defined(XP_OS2)
+/* Work around msvc double optimization bug by making these runtime values; if
+ * they're available at compile time, msvc optimizes division by them by
+ * computing the reciprocal and multiplying instead of dividing - this loses
+ * when the reciprocal isn't representable in a double.
+ */
+static jsdouble msPerSecond = 1000.0;
+static jsdouble msPerDay = SecondsPerDay * 1000.0;
+static jsdouble msPerHour = SecondsPerHour * 1000.0;
+static jsdouble msPerMinute = SecondsPerMinute * 1000.0;
+#else
+#define msPerDay (SecondsPerDay * msPerSecond)
+#define msPerHour (SecondsPerHour * msPerSecond)
+#define msPerMinute (SecondsPerMinute * msPerSecond)
+#define msPerSecond 1000.0
+#endif
+
+#define Day(t) floor((t) / msPerDay)
+
+static jsdouble
+TimeWithinDay(jsdouble t)
+{
+ jsdouble result;
+ result = fmod(t, msPerDay);
+ if (result < 0)
+ result += msPerDay;
+ return result;
+}
+
+#define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
+ ? 366 : 365)
+
+/* math here has to be f.p, because we need
+ * floor((1968 - 1969) / 4) == -1
+ */
+#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
+ - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
+#define TimeFromYear(y) (DayFromYear(y) * msPerDay)
+
+static jsint
+YearFromTime(jsdouble t)
+{
+ jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
+ jsdouble t2 = (jsdouble) TimeFromYear(y);
+
+ if (t2 > t) {
+ y--;
+ } else {
+ if (t2 + msPerDay * DaysInYear(y) <= t)
+ y++;
+ }
+ return y;
+}
+
+#define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
+
+#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
+
+/*
+ * The following array contains the day of year for the first day of
+ * each month, where index 0 is January, and day 0 is January 1.
+ */
+static jsdouble firstDayOfMonth[2][12] = {
+ {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
+ {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
+};
+
+#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m];
+
+static intN
+MonthFromTime(jsdouble t)
+{
+ intN d, step;
+ jsint year = YearFromTime(t);
+ d = DayWithinYear(t, year);
+
+ if (d < (step = 31))
+ return 0;
+ step += (InLeapYear(t) ? 29 : 28);
+ if (d < step)
+ return 1;
+ if (d < (step += 31))
+ return 2;
+ if (d < (step += 30))
+ return 3;
+ if (d < (step += 31))
+ return 4;
+ if (d < (step += 30))
+ return 5;
+ if (d < (step += 31))
+ return 6;
+ if (d < (step += 31))
+ return 7;
+ if (d < (step += 30))
+ return 8;
+ if (d < (step += 31))
+ return 9;
+ if (d < (step += 30))
+ return 10;
+ return 11;
+}
+
+static intN
+DateFromTime(jsdouble t)
+{
+ intN d, step, next;
+ jsint year = YearFromTime(t);
+ d = DayWithinYear(t, year);
+
+ if (d <= (next = 30))
+ return d + 1;
+ step = next;
+ next += (InLeapYear(t) ? 29 : 28);
+ if (d <= next)
+ return d - step;
+ step = next;
+ if (d <= (next += 31))
+ return d - step;
+ step = next;
+ if (d <= (next += 30))
+ return d - step;
+ step = next;
+ if (d <= (next += 31))
+ return d - step;
+ step = next;
+ if (d <= (next += 30))
+ return d - step;
+ step = next;
+ if (d <= (next += 31))
+ return d - step;
+ step = next;
+ if (d <= (next += 31))
+ return d - step;
+ step = next;
+ if (d <= (next += 30))
+ return d - step;
+ step = next;
+ if (d <= (next += 31))
+ return d - step;
+ step = next;
+ if (d <= (next += 30))
+ return d - step;
+ step = next;
+ return d - step;
+}
+
+static intN
+WeekDay(jsdouble t)
+{
+ jsint result;
+ result = (jsint) Day(t) + 4;
+ result = result % 7;
+ if (result < 0)
+ result += 7;
+ return (intN) result;
+}
+
+/* LocalTZA gets set by js_InitDateClass() */
+static jsdouble LocalTZA;
+
+static jsdouble
+DaylightSavingTA(jsdouble t)
+{
+ volatile int64 PR_t;
+ int64 ms2us;
+ int64 offset;
+ jsdouble result;
+
+ /* abort if NaN */
+ if (JSDOUBLE_IS_NaN(t))
+ return t;
+
+ /* put our t in an LL, and map it to usec for prtime */
+ JSLL_D2L(PR_t, t);
+ JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC);
+ JSLL_MUL(PR_t, PR_t, ms2us);
+
+ offset = PRMJ_DSTOffset(PR_t);
+
+ JSLL_DIV(offset, offset, ms2us);
+ JSLL_L2D(result, offset);
+ return result;
+}
+
+
+#define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay)
+
+#define LocalTime(t) ((t) + AdjustTime(t))
+
+static jsdouble
+UTC(jsdouble t)
+{
+ return t - AdjustTime(t - LocalTZA);
+}
+
+static intN
+HourFromTime(jsdouble t)
+{
+ intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
+ if (result < 0)
+ result += (intN)HoursPerDay;
+ return result;
+}
+
+static intN
+MinFromTime(jsdouble t)
+{
+ intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
+ if (result < 0)
+ result += (intN)MinutesPerHour;
+ return result;
+}
+
+static intN
+SecFromTime(jsdouble t)
+{
+ intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
+ if (result < 0)
+ result += (intN)SecondsPerMinute;
+ return result;
+}
+
+static intN
+msFromTime(jsdouble t)
+{
+ intN result = (intN) fmod(t, msPerSecond);
+ if (result < 0)
+ result += (intN)msPerSecond;
+ return result;
+}
+
+#define MakeTime(hour, min, sec, ms) \
+(((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms)
+
+static jsdouble
+MakeDay(jsdouble year, jsdouble month, jsdouble date)
+{
+ jsdouble result;
+ JSBool leap;
+ jsdouble yearday;
+ jsdouble monthday;
+
+ year += floor(month / 12);
+
+ month = fmod(month, 12.0);
+ if (month < 0)
+ month += 12;
+
+ leap = (DaysInYear((jsint) year) == 366);
+
+ yearday = floor(TimeFromYear(year) / msPerDay);
+ monthday = DayFromMonth(month, leap);
+
+ result = yearday
+ + monthday
+ + date - 1;
+ return result;
+}
+
+#define MakeDate(day, time) (day * msPerDay + time)
+
+#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
+ && !((d < 0 ? -d : d) > HalfTimeDomain)) \
+ ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN)
+
+/**
+ * end of ECMA 'support' functions
+ */
+
+/*
+ * Other Support routines and definitions
+ */
+
+static JSClass date_class = {
+ js_Date_str,
+ JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+/* for use by date_parse */
+
+static const char* wtb[] = {
+ "am", "pm",
+ "monday", "tuesday", "wednesday", "thursday", "friday",
+ "saturday", "sunday",
+ "january", "february", "march", "april", "may", "june",
+ "july", "august", "september", "october", "november", "december",
+ "gmt", "ut", "utc",
+ "est", "edt",
+ "cst", "cdt",
+ "mst", "mdt",
+ "pst", "pdt"
+ /* time zone table needs to be expanded */
+};
+
+static int ttb[] = {
+ -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
+ 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
+ 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
+ 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
+ 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
+};
+
+/* helper for date_parse */
+static JSBool
+date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
+ int count, int ignoreCase)
+{
+ JSBool result = JS_FALSE;
+ /* return true if matches, otherwise, false */
+
+ while (count > 0 && s1[s1off] && s2[s2off]) {
+ if (ignoreCase) {
+ if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) {
+ break;
+ }
+ } else {
+ if ((jschar)s1[s1off] != s2[s2off]) {
+ break;
+ }
+ }
+ s1off++;
+ s2off++;
+ count--;
+ }
+
+ if (count == 0) {
+ result = JS_TRUE;
+ }
+
+ return result;
+}
+
+/* find UTC time from given date... no 1900 correction! */
+static jsdouble
+date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour,
+ jsdouble min, jsdouble sec, jsdouble msec)
+{
+ jsdouble day;
+ jsdouble msec_time;
+ jsdouble result;
+
+ day = MakeDay(year, mon, mday);
+ msec_time = MakeTime(hour, min, sec, msec);
+ result = MakeDate(day, msec_time);
+ return result;
+}
+
+/*
+ * See ECMA 15.9.4.[3-10];
+ */
+/* XXX this function must be above date_parseString to avoid a
+ horrid bug in the Win16 1.52 compiler */
+#define MAXARGS 7
+static JSBool
+date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble array[MAXARGS];
+ uintN loop;
+ jsdouble d;
+
+ for (loop = 0; loop < MAXARGS; loop++) {
+ if (loop < argc) {
+ if (!js_ValueToNumber(cx, argv[loop], &d))
+ return JS_FALSE;
+ /* return NaN if any arg is NaN */
+ if (!JSDOUBLE_IS_FINITE(d)) {
+ return js_NewNumberValue(cx, d, rval);
+ }
+ array[loop] = floor(d);
+ } else {
+ array[loop] = 0;
+ }
+ }
+
+ /* adjust 2-digit years into the 20th century */
+ if (array[0] >= 0 && array[0] <= 99)
+ array[0] += 1900;
+
+ /* if we got a 0 for 'date' (which is out of range)
+ * pretend it's a 1. (So Date.UTC(1972, 5) works) */
+ if (array[2] < 1)
+ array[2] = 1;
+
+ d = date_msecFromDate(array[0], array[1], array[2],
+ array[3], array[4], array[5], array[6]);
+ d = TIMECLIP(d);
+
+ return js_NewNumberValue(cx, d, rval);
+}
+
+static JSBool
+date_parseString(JSString *str, jsdouble *result)
+{
+ jsdouble msec;
+
+ const jschar *s = JSSTRING_CHARS(str);
+ size_t limit = JSSTRING_LENGTH(str);
+ size_t i = 0;
+ int year = -1;
+ int mon = -1;
+ int mday = -1;
+ int hour = -1;
+ int min = -1;
+ int sec = -1;
+ int c = -1;
+ int n = -1;
+ jsdouble tzoffset = -1; /* was an int, overflowed on win16!!! */
+ int prevc = 0;
+ JSBool seenplusminus = JS_FALSE;
+
+ if (limit == 0)
+ goto syntax;
+ while (i < limit) {
+ c = s[i];
+ i++;
+ if (c <= ' ' || c == ',' || c == '-') {
+ if (c == '-' && '0' <= s[i] && s[i] <= '9') {
+ prevc = c;
+ }
+ continue;
+ }
+ if (c == '(') { /* comments) */
+ int depth = 1;
+ while (i < limit) {
+ c = s[i];
+ i++;
+ if (c == '(') depth++;
+ else if (c == ')')
+ if (--depth <= 0)
+ break;
+ }
+ continue;
+ }
+ if ('0' <= c && c <= '9') {
+ n = c - '0';
+ while (i < limit && '0' <= (c = s[i]) && c <= '9') {
+ n = n * 10 + c - '0';
+ i++;
+ }
+
+ /* allow TZA before the year, so
+ * 'Wed Nov 05 21:49:11 GMT-0800 1997'
+ * works */
+
+ /* uses of seenplusminus allow : in TZA, so Java
+ * no-timezone style of GMT+4:30 works
+ */
+
+ if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
+ /* make ':' case below change tzoffset */
+ seenplusminus = JS_TRUE;
+
+ /* offset */
+ if (n < 24)
+ n = n * 60; /* EG. "GMT-3" */
+ else
+ n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
+ if (prevc == '+') /* plus means east of GMT */
+ n = -n;
+ if (tzoffset != 0 && tzoffset != -1)
+ goto syntax;
+ tzoffset = n;
+ } else if (n >= 70 ||
+ (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
+ if (year >= 0)
+ goto syntax;
+ else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
+ year = n < 100 ? n + 1900 : n;
+ else
+ goto syntax;
+ } else if (c == ':') {
+ if (hour < 0)
+ hour = /*byte*/ n;
+ else if (min < 0)
+ min = /*byte*/ n;
+ else
+ goto syntax;
+ } else if (c == '/') {
+ if (mon < 0)
+ mon = /*byte*/ n-1;
+ else if (mday < 0)
+ mday = /*byte*/ n;
+ else
+ goto syntax;
+ } else if (i < limit && c != ',' && c > ' ' && c != '-') {
+ goto syntax;
+ } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
+ if (tzoffset < 0)
+ tzoffset -= n;
+ else
+ tzoffset += n;
+ } else if (hour >= 0 && min < 0) {
+ min = /*byte*/ n;
+ } else if (min >= 0 && sec < 0) {
+ sec = /*byte*/ n;
+ } else if (mday < 0) {
+ mday = /*byte*/ n;
+ } else {
+ goto syntax;
+ }
+ prevc = 0;
+ } else if (c == '/' || c == ':' || c == '+' || c == '-') {
+ prevc = c;
+ } else {
+ size_t st = i - 1;
+ int k;
+ while (i < limit) {
+ c = s[i];
+ if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
+ break;
+ i++;
+ }
+ if (i <= st + 1)
+ goto syntax;
+ for (k = (sizeof(wtb)/sizeof(char*)); --k >= 0;)
+ if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
+ int action = ttb[k];
+ if (action != 0) {
+ if (action < 0) {
+ /*
+ * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
+ * 12:30, instead of blindly adding 12 if PM.
+ */
+ JS_ASSERT(action == -1 || action == -2);
+ if (hour > 12 || hour < 0) {
+ goto syntax;
+ } else {
+ if (action == -1 && hour == 12) { /* am */
+ hour = 0;
+ } else if (action == -2 && hour != 12) { /* pm */
+ hour += 12;
+ }
+ }
+ } else if (action <= 13) { /* month! */
+ if (mon < 0) {
+ mon = /*byte*/ (action - 2);
+ } else {
+ goto syntax;
+ }
+ } else {
+ tzoffset = action - 10000;
+ }
+ }
+ break;
+ }
+ if (k < 0)
+ goto syntax;
+ prevc = 0;
+ }
+ }
+ if (year < 0 || mon < 0 || mday < 0)
+ goto syntax;
+ if (sec < 0)
+ sec = 0;
+ if (min < 0)
+ min = 0;
+ if (hour < 0)
+ hour = 0;
+ if (tzoffset == -1) { /* no time zone specified, have to use local */
+ jsdouble msec_time;
+ msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
+
+ *result = UTC(msec_time);
+ return JS_TRUE;
+ }
+
+ msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
+ msec += tzoffset * msPerMinute;
+ *result = msec;
+ return JS_TRUE;
+
+syntax:
+ /* syntax error */
+ *result = 0;
+ return JS_FALSE;
+}
+
+static JSBool
+date_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ jsdouble result;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ if (!date_parseString(str, &result)) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ return JS_TRUE;
+ }
+
+ result = TIMECLIP(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_now(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ int64 us, ms, us2ms;
+ jsdouble msec_time;
+
+ us = PRMJ_Now();
+ JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
+ JSLL_DIV(ms, us, us2ms);
+ JSLL_L2D(msec_time, ms);
+
+ return js_NewDoubleValue(cx, msec_time, rval);
+}
+
+/*
+ * Check that obj is an object of class Date, and get the date value.
+ * Return NULL on failure.
+ */
+static jsdouble *
+date_getProlog(JSContext *cx, JSObject *obj, jsval *argv)
+{
+ if (!JS_InstanceOf(cx, obj, &date_class, argv))
+ return NULL;
+ return JSVAL_TO_DOUBLE(OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE));
+}
+
+/*
+ * See ECMA 15.9.5.4 thru 15.9.5.23
+ */
+static JSBool
+date_getTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ return js_NewNumberValue(cx, *date, rval);
+}
+
+static JSBool
+date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = YearFromTime(LocalTime(result));
+
+ /*
+ * During the great date rewrite of 1.3, we tried to track the evolving ECMA
+ * standard, which then had a definition of getYear which always subtracted
+ * 1900. Which we implemented, not realizing that it was incompatible with
+ * the old behavior... now, rather than thrash the behavior yet again,
+ * we've decided to leave it with the - 1900 behavior and point people to
+ * the getFullYear method. But we try to protect existing scripts that
+ * have specified a version...
+ */
+ if (cx->version == JSVERSION_1_0 ||
+ cx->version == JSVERSION_1_1 ||
+ cx->version == JSVERSION_1_2)
+ {
+ if (result >= 1900 && result < 2000)
+ result -= 1900;
+ } else {
+ result -= 1900;
+ }
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = YearFromTime(LocalTime(result));
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = YearFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = MonthFromTime(LocalTime(result));
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getUTCMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = MonthFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = LocalTime(result);
+ result = DateFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getUTCDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = DateFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = LocalTime(result);
+ result = WeekDay(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = WeekDay(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = HourFromTime(LocalTime(result));
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = HourFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = MinFromTime(LocalTime(result));
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = MinFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+/* Date.getSeconds is mapped to getUTCSeconds */
+
+static JSBool
+date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = SecFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+/* Date.getMilliseconds is mapped to getUTCMilliseconds */
+
+static JSBool
+date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ result = msFromTime(result);
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_getTimezoneOffset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ result = *date;
+
+ /*
+ * Return the time zone offset in minutes for the current locale
+ * that is appropriate for this time. This value would be a
+ * constant except for daylight savings time.
+ */
+ result = (result - LocalTime(result)) / msPerMinute;
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_setTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble result;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ if (!js_ValueToNumber(cx, argv[0], &result))
+ return JS_FALSE;
+
+ result = TIMECLIP(result);
+
+ *date = result;
+ return js_NewNumberValue(cx, result, rval);
+}
+
+static JSBool
+date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ uintN maxargs, JSBool local, jsval *rval)
+{
+ uintN i;
+ jsdouble args[4], *argp, *stop;
+ jsdouble hour, min, sec, msec;
+ jsdouble lorutime; /* Local or UTC version of *date */
+
+ jsdouble msec_time;
+ jsdouble result;
+
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ result = *date;
+
+ /* just return NaN if the date is already NaN */
+ if (!JSDOUBLE_IS_FINITE(result))
+ return js_NewNumberValue(cx, result, rval);
+
+ /* Satisfy the ECMA rule that if a function is called with
+ * fewer arguments than the specified formal arguments, the
+ * remaining arguments are set to undefined. Seems like all
+ * the Date.setWhatever functions in ECMA are only varargs
+ * beyond the first argument; this should be set to undefined
+ * if it's not given. This means that "d = new Date();
+ * d.setMilliseconds()" returns NaN. Blech.
+ */
+ if (argc == 0)
+ argc = 1; /* should be safe, because length of all setters is 1 */
+ else if (argc > maxargs)
+ argc = maxargs; /* clamp argc */
+
+ for (i = 0; i < argc; i++) {
+ if (!js_ValueToNumber(cx, argv[i], &args[i]))
+ return JS_FALSE;
+ if (!JSDOUBLE_IS_FINITE(args[i])) {
+ *date = *cx->runtime->jsNaN;
+ return js_NewNumberValue(cx, *date, rval);
+ }
+ args[i] = js_DoubleToInteger(args[i]);
+ }
+
+ if (local)
+ lorutime = LocalTime(result);
+ else
+ lorutime = result;
+
+ argp = args;
+ stop = argp + argc;
+ if (maxargs >= 4 && argp < stop)
+ hour = *argp++;
+ else
+ hour = HourFromTime(lorutime);
+
+ if (maxargs >= 3 && argp < stop)
+ min = *argp++;
+ else
+ min = MinFromTime(lorutime);
+
+ if (maxargs >= 2 && argp < stop)
+ sec = *argp++;
+ else
+ sec = SecFromTime(lorutime);
+
+ if (maxargs >= 1 && argp < stop)
+ msec = *argp;
+ else
+ msec = msFromTime(lorutime);
+
+ msec_time = MakeTime(hour, min, sec, msec);
+ result = MakeDate(Day(lorutime), msec_time);
+
+/* fprintf(stderr, "%f\n", result); */
+
+ if (local)
+ result = UTC(result);
+
+/* fprintf(stderr, "%f\n", result); */
+
+ *date = TIMECLIP(result);
+ return js_NewNumberValue(cx, *date, rval);
+}
+
+static JSBool
+date_setMilliseconds(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 1, JS_TRUE, rval);
+}
+
+static JSBool
+date_setUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 1, JS_FALSE, rval);
+}
+
+static JSBool
+date_setSeconds(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 2, JS_TRUE, rval);
+}
+
+static JSBool
+date_setUTCSeconds(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 2, JS_FALSE, rval);
+}
+
+static JSBool
+date_setMinutes(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 3, JS_TRUE, rval);
+}
+
+static JSBool
+date_setUTCMinutes(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 3, JS_FALSE, rval);
+}
+
+static JSBool
+date_setHours(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 4, JS_TRUE, rval);
+}
+
+static JSBool
+date_setUTCHours(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeTime(cx, obj, argc, argv, 4, JS_FALSE, rval);
+}
+
+static JSBool
+date_makeDate(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, uintN maxargs, JSBool local, jsval *rval)
+{
+ uintN i;
+ jsdouble lorutime; /* local or UTC version of *date */
+ jsdouble args[3], *argp, *stop;
+ jsdouble year, month, day;
+ jsdouble result;
+
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ result = *date;
+
+ /* see complaint about ECMA in date_MakeTime */
+ if (argc == 0)
+ argc = 1; /* should be safe, because length of all setters is 1 */
+ else if (argc > maxargs)
+ argc = maxargs; /* clamp argc */
+
+ for (i = 0; i < argc; i++) {
+ if (!js_ValueToNumber(cx, argv[i], &args[i]))
+ return JS_FALSE;
+ if (!JSDOUBLE_IS_FINITE(args[i])) {
+ *date = *cx->runtime->jsNaN;
+ return js_NewNumberValue(cx, *date, rval);
+ }
+ args[i] = js_DoubleToInteger(args[i]);
+ }
+
+ /* return NaN if date is NaN and we're not setting the year,
+ * If we are, use 0 as the time. */
+ if (!(JSDOUBLE_IS_FINITE(result))) {
+ if (argc < 3)
+ return js_NewNumberValue(cx, result, rval);
+ else
+ lorutime = +0.;
+ } else {
+ if (local)
+ lorutime = LocalTime(result);
+ else
+ lorutime = result;
+ }
+
+ argp = args;
+ stop = argp + argc;
+ if (maxargs >= 3 && argp < stop)
+ year = *argp++;
+ else
+ year = YearFromTime(lorutime);
+
+ if (maxargs >= 2 && argp < stop)
+ month = *argp++;
+ else
+ month = MonthFromTime(lorutime);
+
+ if (maxargs >= 1 && argp < stop)
+ day = *argp++;
+ else
+ day = DateFromTime(lorutime);
+
+ day = MakeDay(year, month, day); /* day within year */
+ result = MakeDate(day, TimeWithinDay(lorutime));
+
+ if (local)
+ result = UTC(result);
+
+ *date = TIMECLIP(result);
+ return js_NewNumberValue(cx, *date, rval);
+}
+
+static JSBool
+date_setDate(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeDate(cx, obj, argc, argv, 1, JS_TRUE, rval);
+}
+
+static JSBool
+date_setUTCDate(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeDate(cx, obj, argc, argv, 1, JS_FALSE, rval);
+}
+
+static JSBool
+date_setMonth(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeDate(cx, obj, argc, argv, 2, JS_TRUE, rval);
+}
+
+static JSBool
+date_setUTCMonth(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeDate(cx, obj, argc, argv, 2, JS_FALSE, rval);
+}
+
+static JSBool
+date_setFullYear(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeDate(cx, obj, argc, argv, 3, JS_TRUE, rval);
+}
+
+static JSBool
+date_setUTCFullYear(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_makeDate(cx, obj, argc, argv, 3, JS_FALSE, rval);
+}
+
+static JSBool
+date_setYear(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ jsdouble t;
+ jsdouble year;
+ jsdouble day;
+ jsdouble result;
+
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ result = *date;
+
+ if (!js_ValueToNumber(cx, argv[0], &year))
+ return JS_FALSE;
+ if (!JSDOUBLE_IS_FINITE(year)) {
+ *date = *cx->runtime->jsNaN;
+ return js_NewNumberValue(cx, *date, rval);
+ }
+
+ year = js_DoubleToInteger(year);
+
+ if (!JSDOUBLE_IS_FINITE(result)) {
+ t = +0.0;
+ } else {
+ t = LocalTime(result);
+ }
+
+ if (year >= 0 && year <= 99)
+ year += 1900;
+
+ day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
+ result = MakeDate(day, TimeWithinDay(t));
+ result = UTC(result);
+
+ *date = TIMECLIP(result);
+ return js_NewNumberValue(cx, *date, rval);
+}
+
+/* constants for toString, toUTCString */
+static char js_NaN_date_str[] = "Invalid Date";
+static const char* days[] =
+{
+ "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
+};
+static const char* months[] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static JSBool
+date_toGMTString(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ char buf[100];
+ JSString *str;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ if (!JSDOUBLE_IS_FINITE(*date)) {
+ JS_snprintf(buf, sizeof buf, js_NaN_date_str);
+ } else {
+ jsdouble temp = *date;
+
+ /* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
+ * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
+ */
+ JS_snprintf(buf, sizeof buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
+ days[WeekDay(temp)],
+ DateFromTime(temp),
+ months[MonthFromTime(temp)],
+ YearFromTime(temp),
+ HourFromTime(temp),
+ MinFromTime(temp),
+ SecFromTime(temp));
+ }
+ str = JS_NewStringCopyZ(cx, buf);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+/* for Date.toLocaleString; interface to PRMJTime date struct.
+ * If findEquivalent is true, then try to map the year to an equivalent year
+ * that's in range.
+ */
+static void
+new_explode(jsdouble timeval, PRMJTime *split, JSBool findEquivalent)
+{
+ jsint year = YearFromTime(timeval);
+ int16 adjustedYear;
+
+ /* If the year doesn't fit in a PRMJTime, find something to do about it. */
+ if (year > 32767 || year < -32768) {
+ if (findEquivalent) {
+ /* We're really just trying to get a timezone string; map the year
+ * to some equivalent year in the range 0 to 2800. Borrowed from
+ * A. D. Olsen.
+ */
+ jsint cycles;
+#define CYCLE_YEARS 2800L
+ cycles = (year >= 0) ? year / CYCLE_YEARS
+ : -1 - (-1 - year) / CYCLE_YEARS;
+ adjustedYear = (int16)(year - cycles * CYCLE_YEARS);
+ } else {
+ /* Clamp it to the nearest representable year. */
+ adjustedYear = (int16)((year > 0) ? 32767 : - 32768);
+ }
+ } else {
+ adjustedYear = (int16)year;
+ }
+
+ split->tm_usec = (int32) msFromTime(timeval) * 1000;
+ split->tm_sec = (int8) SecFromTime(timeval);
+ split->tm_min = (int8) MinFromTime(timeval);
+ split->tm_hour = (int8) HourFromTime(timeval);
+ split->tm_mday = (int8) DateFromTime(timeval);
+ split->tm_mon = (int8) MonthFromTime(timeval);
+ split->tm_wday = (int8) WeekDay(timeval);
+ split->tm_year = (int16) adjustedYear;
+ split->tm_yday = (int16) DayWithinYear(timeval, year);
+
+ /* not sure how this affects things, but it doesn't seem
+ to matter. */
+ split->tm_isdst = (DaylightSavingTA(timeval) != 0);
+}
+
+typedef enum formatspec {
+ FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
+} formatspec;
+
+/* helper function */
+static JSBool
+date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
+{
+ char buf[100];
+ JSString *str;
+ char tzbuf[100];
+ JSBool usetz;
+ size_t i, tzlen;
+ PRMJTime split;
+
+ if (!JSDOUBLE_IS_FINITE(date)) {
+ JS_snprintf(buf, sizeof buf, js_NaN_date_str);
+ } else {
+ jsdouble local = LocalTime(date);
+
+ /* offset from GMT in minutes. The offset includes daylight savings,
+ if it applies. */
+ jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute);
+
+ /* map 510 minutes to 0830 hours */
+ intN offset = (minutes / 60) * 100 + minutes % 60;
+
+ /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
+ * printed as 'GMT-0800' rather than as 'PST' to avoid
+ * operating-system dependence on strftime (which
+ * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
+ * PST as 'Pacific Standard Time.' This way we always know
+ * what we're getting, and can parse it if we produce it.
+ * The OS TZA string is included as a comment.
+ */
+
+ /* get a timezone string from the OS to include as a
+ comment. */
+ new_explode(date, &split, JS_TRUE);
+ if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
+
+ /* Decide whether to use the resulting timezone string.
+ *
+ * Reject it if it contains any non-ASCII, non-alphanumeric
+ * characters. It's then likely in some other character
+ * encoding, and we probably won't display it correctly.
+ */
+ usetz = JS_TRUE;
+ tzlen = strlen(tzbuf);
+ if (tzlen > 100) {
+ usetz = JS_FALSE;
+ } else {
+ for (i = 0; i < tzlen; i++) {
+ jschar c = tzbuf[i];
+ if (c > 127 ||
+ !(isalpha(c) || isdigit(c) ||
+ c == ' ' || c == '(' || c == ')')) {
+ usetz = JS_FALSE;
+ }
+ }
+ }
+
+ /* Also reject it if it's not parenthesized or if it's '()'. */
+ if (tzbuf[0] != '(' || tzbuf[1] == ')')
+ usetz = JS_FALSE;
+ } else
+ usetz = JS_FALSE;
+
+ switch (format) {
+ case FORMATSPEC_FULL:
+ /*
+ * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
+ * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
+ */
+ /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
+ JS_snprintf(buf, sizeof buf,
+ "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
+ days[WeekDay(local)],
+ months[MonthFromTime(local)],
+ DateFromTime(local),
+ YearFromTime(local),
+ HourFromTime(local),
+ MinFromTime(local),
+ SecFromTime(local),
+ offset,
+ usetz ? " " : "",
+ usetz ? tzbuf : "");
+ break;
+ case FORMATSPEC_DATE:
+ /* Tue Oct 31 2000 */
+ JS_snprintf(buf, sizeof buf,
+ "%s %s %.2d %.4d",
+ days[WeekDay(local)],
+ months[MonthFromTime(local)],
+ DateFromTime(local),
+ YearFromTime(local));
+ break;
+ case FORMATSPEC_TIME:
+ /* 09:41:40 GMT-0800 (PST) */
+ JS_snprintf(buf, sizeof buf,
+ "%.2d:%.2d:%.2d GMT%+.4d%s%s",
+ HourFromTime(local),
+ MinFromTime(local),
+ SecFromTime(local),
+ offset,
+ usetz ? " " : "",
+ usetz ? tzbuf : "");
+ break;
+ }
+ }
+
+ str = JS_NewStringCopyZ(cx, buf);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval, char *format)
+{
+ char buf[100];
+ JSString *str;
+ PRMJTime split;
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ if (!JSDOUBLE_IS_FINITE(*date)) {
+ JS_snprintf(buf, sizeof buf, js_NaN_date_str);
+ } else {
+ intN result_len;
+ jsdouble local = LocalTime(*date);
+ new_explode(local, &split, JS_FALSE);
+
+ /* let PRMJTime format it. */
+ result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
+
+ /* If it failed, default to toString. */
+ if (result_len == 0)
+ return date_format(cx, *date, FORMATSPEC_FULL, rval);
+
+ /* Hacked check against undesired 2-digit year 00/00/00 form. */
+ if (buf[result_len - 3] == '/' &&
+ isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1])) {
+ JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
+ "%d", js_DateGetYear(cx, obj));
+ }
+
+ }
+
+ str = JS_NewStringCopyZ(cx, buf);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ /* Use '%#c' for windows, because '%c' is
+ * backward-compatible and non-y2k with msvc; '%#c' requests that a
+ * full year be used in the result string.
+ */
+ return date_toLocaleHelper(cx, obj, argc, argv, rval,
+#if defined(_WIN32) && !defined(__MWERKS__)
+ "%#c"
+#else
+ "%c"
+#endif
+ );
+}
+
+static JSBool
+date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ /* Use '%#x' for windows, because '%x' is
+ * backward-compatible and non-y2k with msvc; '%#x' requests that a
+ * full year be used in the result string.
+ */
+ return date_toLocaleHelper(cx, obj, argc, argv, rval,
+#if defined(_WIN32) && !defined(__MWERKS__)
+ "%#x"
+#else
+ "%x"
+#endif
+ );
+}
+
+static JSBool
+date_toLocaleTimeString(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ return date_toLocaleHelper(cx, obj, argc, argv, rval, "%X");
+}
+
+static JSBool
+date_toTimeString(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ return date_format(cx, *date, FORMATSPEC_TIME, rval);
+}
+
+static JSBool
+date_toDateString(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ return date_format(cx, *date, FORMATSPEC_DATE, rval);
+}
+
+#if JS_HAS_TOSOURCE
+#include <string.h>
+#include "jsdtoa.h"
+
+static JSBool
+date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble *date;
+ char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes;
+ JSString *str;
+
+ date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+
+ numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, *date);
+ if (!numStr) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+
+ bytes = JS_smprintf("(new %s(%s))", date_class.name, numStr);
+ if (!bytes) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+
+ str = JS_NewString(cx, bytes, strlen(bytes));
+ if (!str) {
+ free(bytes);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif
+
+static JSBool
+date_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsdouble *date = date_getProlog(cx, obj, argv);
+ if (!date)
+ return JS_FALSE;
+ return date_format(cx, *date, FORMATSPEC_FULL, rval);
+}
+
+#if JS_HAS_VALUEOF_HINT
+static JSBool
+date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ /* It is an error to call date_valueOf on a non-date object, but we don't
+ * need to check for that explicitly here because every path calls
+ * date_getProlog, which does the check.
+ */
+
+ /* If called directly with no arguments, convert to a time number. */
+ if (argc == 0)
+ return date_getTime(cx, obj, argc, argv, rval);
+
+ /* Convert to number only if the hint was given, otherwise favor string. */
+ if (argc == 1) {
+ JSString *str, *str2;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ str2 = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
+ if (!js_CompareStrings(str, str2))
+ return date_getTime(cx, obj, argc, argv, rval);
+ }
+ return date_toString(cx, obj, argc, argv, rval);
+}
+#else
+#define date_valueOf date_getTime
+#endif
+
+
+/*
+ * creation and destruction
+ */
+
+static JSFunctionSpec date_static_methods[] = {
+ {"UTC", date_UTC, MAXARGS,0,0 },
+ {"parse", date_parse, 1,0,0 },
+ {"now", date_now, 0,0,0 },
+ {0,0,0,0,0}
+};
+
+static JSFunctionSpec date_methods[] = {
+ {"getTime", date_getTime, 0,0,0 },
+ {"getTimezoneOffset", date_getTimezoneOffset, 0,0,0 },
+ {"getYear", date_getYear, 0,0,0 },
+ {"getFullYear", date_getFullYear, 0,0,0 },
+ {"getUTCFullYear", date_getUTCFullYear, 0,0,0 },
+ {"getMonth", date_getMonth, 0,0,0 },
+ {"getUTCMonth", date_getUTCMonth, 0,0,0 },
+ {"getDate", date_getDate, 0,0,0 },
+ {"getUTCDate", date_getUTCDate, 0,0,0 },
+ {"getDay", date_getDay, 0,0,0 },
+ {"getUTCDay", date_getUTCDay, 0,0,0 },
+ {"getHours", date_getHours, 0,0,0 },
+ {"getUTCHours", date_getUTCHours, 0,0,0 },
+ {"getMinutes", date_getMinutes, 0,0,0 },
+ {"getUTCMinutes", date_getUTCMinutes, 0,0,0 },
+ {"getSeconds", date_getUTCSeconds, 0,0,0 },
+ {"getUTCSeconds", date_getUTCSeconds, 0,0,0 },
+ {"getMilliseconds", date_getUTCMilliseconds,0,0,0 },
+ {"getUTCMilliseconds", date_getUTCMilliseconds,0,0,0 },
+ {"setTime", date_setTime, 1,0,0 },
+ {"setYear", date_setYear, 1,0,0 },
+ {"setFullYear", date_setFullYear, 3,0,0 },
+ {"setUTCFullYear", date_setUTCFullYear, 3,0,0 },
+ {"setMonth", date_setMonth, 2,0,0 },
+ {"setUTCMonth", date_setUTCMonth, 2,0,0 },
+ {"setDate", date_setDate, 1,0,0 },
+ {"setUTCDate", date_setUTCDate, 1,0,0 },
+ {"setHours", date_setHours, 4,0,0 },
+ {"setUTCHours", date_setUTCHours, 4,0,0 },
+ {"setMinutes", date_setMinutes, 3,0,0 },
+ {"setUTCMinutes", date_setUTCMinutes, 3,0,0 },
+ {"setSeconds", date_setSeconds, 2,0,0 },
+ {"setUTCSeconds", date_setUTCSeconds, 2,0,0 },
+ {"setMilliseconds", date_setMilliseconds, 1,0,0 },
+ {"setUTCMilliseconds", date_setUTCMilliseconds,1,0,0 },
+ {"toUTCString", date_toGMTString, 0,0,0 },
+ {js_toLocaleString_str, date_toLocaleString, 0,0,0 },
+ {"toLocaleDateString", date_toLocaleDateString,0,0,0 },
+ {"toLocaleTimeString", date_toLocaleTimeString,0,0,0 },
+ {"toDateString", date_toDateString, 0,0,0 },
+ {"toTimeString", date_toTimeString, 0,0,0 },
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, date_toSource, 0,0,0 },
+#endif
+ {js_toString_str, date_toString, 0,0,0 },
+ {js_valueOf_str, date_valueOf, 0,0,0 },
+ {0,0,0,0,0}
+};
+
+static jsdouble *
+date_constructor(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date;
+
+ date = js_NewDouble(cx, 0.0);
+ if (!date)
+ return NULL;
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, DOUBLE_TO_JSVAL(date));
+ return date;
+}
+
+static JSBool
+Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble *date;
+ JSString *str;
+ jsdouble d;
+
+ /* Date called as function */
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ int64 us, ms, us2ms;
+ jsdouble msec_time;
+
+ /* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
+ * so compute ms from PRMJ_Now.
+ */
+ us = PRMJ_Now();
+ JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
+ JSLL_DIV(ms, us, us2ms);
+ JSLL_L2D(msec_time, ms);
+
+ return date_format(cx, msec_time, FORMATSPEC_FULL, rval);
+ }
+
+ /* Date called as constructor */
+ if (argc == 0) {
+ int64 us, ms, us2ms;
+ jsdouble msec_time;
+
+ date = date_constructor(cx, obj);
+ if (!date)
+ return JS_FALSE;
+
+ us = PRMJ_Now();
+ JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
+ JSLL_DIV(ms, us, us2ms);
+ JSLL_L2D(msec_time, ms);
+
+ *date = msec_time;
+ } else if (argc == 1) {
+ if (!JSVAL_IS_STRING(argv[0])) {
+ /* the argument is a millisecond number */
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ date = date_constructor(cx, obj);
+ if (!date)
+ return JS_FALSE;
+ *date = TIMECLIP(d);
+ } else {
+ /* the argument is a string; parse it. */
+ date = date_constructor(cx, obj);
+ if (!date)
+ return JS_FALSE;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+
+ if (!date_parseString(str, date))
+ *date = *cx->runtime->jsNaN;
+ *date = TIMECLIP(*date);
+ }
+ } else {
+ jsdouble array[MAXARGS];
+ uintN loop;
+ jsdouble double_arg;
+ jsdouble day;
+ jsdouble msec_time;
+
+ for (loop = 0; loop < MAXARGS; loop++) {
+ if (loop < argc) {
+ if (!js_ValueToNumber(cx, argv[loop], &double_arg))
+ return JS_FALSE;
+ /* if any arg is NaN, make a NaN date object
+ and return */
+ if (!JSDOUBLE_IS_FINITE(double_arg)) {
+ date = date_constructor(cx, obj);
+ if (!date)
+ return JS_FALSE;
+ *date = *cx->runtime->jsNaN;
+ return JS_TRUE;
+ }
+ array[loop] = js_DoubleToInteger(double_arg);
+ } else {
+ if (loop == 2) {
+ array[loop] = 1; /* Default the date argument to 1. */
+ } else {
+ array[loop] = 0;
+ }
+ }
+ }
+
+ date = date_constructor(cx, obj);
+ if (!date)
+ return JS_FALSE;
+
+ /* adjust 2-digit years into the 20th century */
+ if (array[0] >= 0 && array[0] <= 99)
+ array[0] += 1900;
+
+ day = MakeDay(array[0], array[1], array[2]);
+ msec_time = MakeTime(array[3], array[4], array[5], array[6]);
+ msec_time = MakeDate(day, msec_time);
+ msec_time = UTC(msec_time);
+ *date = TIMECLIP(msec_time);
+ }
+ return JS_TRUE;
+}
+
+JSObject *
+js_InitDateClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+ jsdouble *proto_date;
+
+ /* set static LocalTZA */
+ LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
+ proto = JS_InitClass(cx, obj, NULL, &date_class, Date, MAXARGS,
+ NULL, date_methods, NULL, date_static_methods);
+ if (!proto)
+ return NULL;
+
+ /* Alias toUTCString with toGMTString. (ECMA B.2.6) */
+ if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString"))
+ return NULL;
+
+ /* Set the value of the Date.prototype date to NaN */
+ proto_date = date_constructor(cx, proto);
+ if (!proto_date)
+ return NULL;
+ *proto_date = *cx->runtime->jsNaN;
+
+ return proto;
+}
+
+JS_FRIEND_API(JSObject *)
+js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
+{
+ JSObject *obj;
+ jsdouble *date;
+
+ obj = js_NewObject(cx, &date_class, NULL, NULL);
+ if (!obj)
+ return NULL;
+
+ date = date_constructor(cx, obj);
+ if (!date)
+ return NULL;
+
+ *date = msec_time;
+ return obj;
+}
+
+JS_FRIEND_API(JSObject *)
+js_NewDateObject(JSContext* cx, int year, int mon, int mday,
+ int hour, int min, int sec)
+{
+ JSObject *obj;
+ jsdouble msec_time;
+
+ msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
+ obj = js_NewDateObjectMsec(cx, UTC(msec_time));
+ return obj;
+}
+
+JS_FRIEND_API(JSBool)
+js_DateIsValid(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return JS_FALSE;
+ else
+ return JS_TRUE;
+}
+
+JS_FRIEND_API(int)
+js_DateGetYear(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+
+ /* Preserve legacy API behavior of returning 0 for invalid dates. */
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return 0;
+ return (int) YearFromTime(LocalTime(*date));
+}
+
+JS_FRIEND_API(int)
+js_DateGetMonth(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return 0;
+ return (int) MonthFromTime(LocalTime(*date));
+}
+
+JS_FRIEND_API(int)
+js_DateGetDate(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return 0;
+ return (int) DateFromTime(LocalTime(*date));
+}
+
+JS_FRIEND_API(int)
+js_DateGetHours(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return 0;
+ return (int) HourFromTime(LocalTime(*date));
+}
+
+JS_FRIEND_API(int)
+js_DateGetMinutes(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return 0;
+ return (int) MinFromTime(LocalTime(*date));
+}
+
+JS_FRIEND_API(int)
+js_DateGetSeconds(JSContext *cx, JSObject* obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return 0;
+ return (int) SecFromTime(*date);
+}
+
+JS_FRIEND_API(void)
+js_DateSetYear(JSContext *cx, JSObject *obj, int year)
+{
+ jsdouble local;
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+ if (!date)
+ return;
+ local = LocalTime(*date);
+ /* reset date if it was NaN */
+ if (JSDOUBLE_IS_NaN(local))
+ local = 0;
+ local = date_msecFromDate(year,
+ MonthFromTime(local),
+ DateFromTime(local),
+ HourFromTime(local),
+ MinFromTime(local),
+ SecFromTime(local),
+ msFromTime(local));
+ *date = UTC(local);
+}
+
+JS_FRIEND_API(void)
+js_DateSetMonth(JSContext *cx, JSObject *obj, int month)
+{
+ jsdouble local;
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+ if (!date)
+ return;
+ local = LocalTime(*date);
+ /* bail if date was NaN */
+ if (JSDOUBLE_IS_NaN(local))
+ return;
+ local = date_msecFromDate(YearFromTime(local),
+ month,
+ DateFromTime(local),
+ HourFromTime(local),
+ MinFromTime(local),
+ SecFromTime(local),
+ msFromTime(local));
+ *date = UTC(local);
+}
+
+JS_FRIEND_API(void)
+js_DateSetDate(JSContext *cx, JSObject *obj, int date)
+{
+ jsdouble local;
+ jsdouble *datep = date_getProlog(cx, obj, NULL);
+ if (!datep)
+ return;
+ local = LocalTime(*datep);
+ if (JSDOUBLE_IS_NaN(local))
+ return;
+ local = date_msecFromDate(YearFromTime(local),
+ MonthFromTime(local),
+ date,
+ HourFromTime(local),
+ MinFromTime(local),
+ SecFromTime(local),
+ msFromTime(local));
+ *datep = UTC(local);
+}
+
+JS_FRIEND_API(void)
+js_DateSetHours(JSContext *cx, JSObject *obj, int hours)
+{
+ jsdouble local;
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+ if (!date)
+ return;
+ local = LocalTime(*date);
+ if (JSDOUBLE_IS_NaN(local))
+ return;
+ local = date_msecFromDate(YearFromTime(local),
+ MonthFromTime(local),
+ DateFromTime(local),
+ hours,
+ MinFromTime(local),
+ SecFromTime(local),
+ msFromTime(local));
+ *date = UTC(local);
+}
+
+JS_FRIEND_API(void)
+js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes)
+{
+ jsdouble local;
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+ if (!date)
+ return;
+ local = LocalTime(*date);
+ if (JSDOUBLE_IS_NaN(local))
+ return;
+ local = date_msecFromDate(YearFromTime(local),
+ MonthFromTime(local),
+ DateFromTime(local),
+ HourFromTime(local),
+ minutes,
+ SecFromTime(local),
+ msFromTime(local));
+ *date = UTC(local);
+}
+
+JS_FRIEND_API(void)
+js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds)
+{
+ jsdouble local;
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+ if (!date)
+ return;
+ local = LocalTime(*date);
+ if (JSDOUBLE_IS_NaN(local))
+ return;
+ local = date_msecFromDate(YearFromTime(local),
+ MonthFromTime(local),
+ DateFromTime(local),
+ HourFromTime(local),
+ MinFromTime(local),
+ seconds,
+ msFromTime(local));
+ *date = UTC(local);
+}
+
+JS_FRIEND_API(jsdouble)
+js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
+{
+ jsdouble *date = date_getProlog(cx, obj, NULL);
+ if (!date || JSDOUBLE_IS_NaN(*date))
+ return 0;
+ return (*date);
+}
diff --git a/src/dom/js/jsdate.h b/src/dom/js/jsdate.h
new file mode 100644
index 000000000..790b4daf6
--- /dev/null
+++ b/src/dom/js/jsdate.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS Date class interface.
+ */
+
+#ifndef jsdate_h___
+#define jsdate_h___
+
+JS_BEGIN_EXTERN_C
+
+extern JSObject *
+js_InitDateClass(JSContext *cx, JSObject *obj);
+
+/*
+ * These functions provide a C interface to the date/time object
+ */
+
+/*
+ * Construct a new Date Object from a time value given in milliseconds UTC
+ * since the epoch.
+ */
+extern JS_FRIEND_API(JSObject*)
+js_NewDateObjectMsec(JSContext* cx, jsdouble msec_time);
+
+/*
+ * Construct a new Date Object from an exploded local time value.
+ */
+extern JS_FRIEND_API(JSObject*)
+js_NewDateObject(JSContext* cx, int year, int mon, int mday,
+ int hour, int min, int sec);
+
+/*
+ * Detect whether the internal date value is NaN. (Because failure is
+ * out-of-band for js_DateGet*)
+ */
+extern JS_FRIEND_API(JSBool)
+js_DateIsValid(JSContext *cx, JSObject* obj);
+
+extern JS_FRIEND_API(int)
+js_DateGetYear(JSContext *cx, JSObject* obj);
+
+extern JS_FRIEND_API(int)
+js_DateGetMonth(JSContext *cx, JSObject* obj);
+
+extern JS_FRIEND_API(int)
+js_DateGetDate(JSContext *cx, JSObject* obj);
+
+extern JS_FRIEND_API(int)
+js_DateGetHours(JSContext *cx, JSObject* obj);
+
+extern JS_FRIEND_API(int)
+js_DateGetMinutes(JSContext *cx, JSObject* obj);
+
+extern JS_FRIEND_API(int)
+js_DateGetSeconds(JSContext *cx, JSObject* obj);
+
+extern JS_FRIEND_API(void)
+js_DateSetYear(JSContext *cx, JSObject *obj, int year);
+
+extern JS_FRIEND_API(void)
+js_DateSetMonth(JSContext *cx, JSObject *obj, int year);
+
+extern JS_FRIEND_API(void)
+js_DateSetDate(JSContext *cx, JSObject *obj, int date);
+
+extern JS_FRIEND_API(void)
+js_DateSetHours(JSContext *cx, JSObject *obj, int hours);
+
+extern JS_FRIEND_API(void)
+js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes);
+
+extern JS_FRIEND_API(void)
+js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds);
+
+extern JS_FRIEND_API(jsdouble)
+js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj);
+
+JS_END_EXTERN_C
+
+#endif /* jsdate_h___ */
diff --git a/src/dom/js/jsdbgapi.c b/src/dom/js/jsdbgapi.c
new file mode 100644
index 000000000..2aa684941
--- /dev/null
+++ b/src/dom/js/jsdbgapi.c
@@ -0,0 +1,1240 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS debugging API.
+ */
+#include "jsstddef.h"
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsclist.h"
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdbgapi.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+typedef struct JSTrap {
+ JSCList links;
+ JSScript *script;
+ jsbytecode *pc;
+ JSOp op;
+ JSTrapHandler handler;
+ void *closure;
+} JSTrap;
+
+static JSTrap *
+FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
+{
+ JSTrap *trap;
+
+ for (trap = (JSTrap *)rt->trapList.next;
+ trap != (JSTrap *)&rt->trapList;
+ trap = (JSTrap *)trap->links.next) {
+ if (trap->script == script && trap->pc == pc)
+ return trap;
+ }
+ return NULL;
+}
+
+void
+js_PatchOpcode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
+{
+ JSTrap *trap;
+
+ trap = FindTrap(cx->runtime, script, pc);
+ if (trap)
+ trap->op = op;
+ else
+ *pc = (jsbytecode)op;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
+ JSTrapHandler handler, void *closure)
+{
+ JSRuntime *rt;
+ JSTrap *trap;
+
+ rt = cx->runtime;
+ trap = FindTrap(rt, script, pc);
+ if (trap) {
+ JS_ASSERT(trap->script == script && trap->pc == pc);
+ JS_ASSERT(*pc == JSOP_TRAP);
+ } else {
+ trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
+ if (!trap || !js_AddRoot(cx, &trap->closure, "trap->closure")) {
+ if (trap)
+ JS_free(cx, trap);
+ return JS_FALSE;
+ }
+ JS_APPEND_LINK(&trap->links, &rt->trapList);
+ trap->script = script;
+ trap->pc = pc;
+ trap->op = (JSOp)*pc;
+ *pc = JSOP_TRAP;
+ }
+ trap->handler = handler;
+ trap->closure = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSOp)
+JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
+{
+ JSTrap *trap;
+
+ trap = FindTrap(cx->runtime, script, pc);
+ if (!trap) {
+ JS_ASSERT(0); /* XXX can't happen */
+ return JSOP_LIMIT;
+ }
+ return trap->op;
+}
+
+static void
+DestroyTrap(JSContext *cx, JSTrap *trap)
+{
+ JS_REMOVE_LINK(&trap->links);
+ *trap->pc = (jsbytecode)trap->op;
+ js_RemoveRoot(cx->runtime, &trap->closure);
+ JS_free(cx, trap);
+}
+
+JS_PUBLIC_API(void)
+JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
+ JSTrapHandler *handlerp, void **closurep)
+{
+ JSTrap *trap;
+
+ trap = FindTrap(cx->runtime, script, pc);
+ if (handlerp)
+ *handlerp = trap ? trap->handler : NULL;
+ if (closurep)
+ *closurep = trap ? trap->closure : NULL;
+ if (trap)
+ DestroyTrap(cx, trap);
+}
+
+JS_PUBLIC_API(void)
+JS_ClearScriptTraps(JSContext *cx, JSScript *script)
+{
+ JSRuntime *rt;
+ JSTrap *trap, *next;
+
+ rt = cx->runtime;
+ for (trap = (JSTrap *)rt->trapList.next;
+ trap != (JSTrap *)&rt->trapList;
+ trap = next) {
+ next = (JSTrap *)trap->links.next;
+ if (trap->script == script)
+ DestroyTrap(cx, trap);
+ }
+}
+
+JS_PUBLIC_API(void)
+JS_ClearAllTraps(JSContext *cx)
+{
+ JSRuntime *rt;
+ JSTrap *trap, *next;
+
+ rt = cx->runtime;
+ for (trap = (JSTrap *)rt->trapList.next;
+ trap != (JSTrap *)&rt->trapList;
+ trap = next) {
+ next = (JSTrap *)trap->links.next;
+ DestroyTrap(cx, trap);
+ }
+}
+
+JS_PUBLIC_API(JSTrapStatus)
+JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
+{
+ JSTrap *trap;
+ JSTrapStatus status;
+ jsint op;
+
+ trap = FindTrap(cx->runtime, script, pc);
+ if (!trap) {
+ JS_ASSERT(0); /* XXX can't happen */
+ return JSTRAP_ERROR;
+ }
+ /*
+ * It's important that we not use 'trap->' after calling the callback --
+ * the callback might remove the trap!
+ */
+ op = (jsint)trap->op;
+ status = trap->handler(cx, script, pc, rval, trap->closure);
+ if (status == JSTRAP_CONTINUE) {
+ /* By convention, return the true op to the interpreter in rval. */
+ *rval = INT_TO_JSVAL(op);
+ }
+ return status;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
+{
+ rt->interruptHandler = handler;
+ rt->interruptHandlerData = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
+{
+ if (handlerp)
+ *handlerp = (JSTrapHandler)rt->interruptHandler;
+ if (closurep)
+ *closurep = rt->interruptHandlerData;
+ rt->interruptHandler = 0;
+ rt->interruptHandlerData = 0;
+ return JS_TRUE;
+}
+
+/************************************************************************/
+
+typedef struct JSWatchPoint {
+ JSCList links;
+ JSObject *object; /* weak link, see js_FinalizeObject */
+ JSScopeProperty *sprop;
+ JSPropertyOp setter;
+ JSWatchPointHandler handler;
+ void *closure;
+ jsrefcount nrefs;
+} JSWatchPoint;
+
+#define HoldWatchPoint(wp) ((wp)->nrefs++)
+
+static JSBool
+DropWatchPoint(JSContext *cx, JSWatchPoint *wp)
+{
+ JSScopeProperty *sprop;
+
+ if (--wp->nrefs != 0)
+ return JS_TRUE;
+
+ /*
+ * Remove wp from the list, then if there are no other watchpoints for
+ * wp->sprop in any scope, restore wp->sprop->setter from wp.
+ */
+ JS_REMOVE_LINK(&wp->links);
+ sprop = wp->sprop;
+ if (!js_GetWatchedSetter(cx->runtime, NULL, sprop)) {
+ sprop = js_ChangeNativePropertyAttrs(cx, wp->object, sprop,
+ 0, sprop->attrs,
+ sprop->getter, wp->setter);
+ if (!sprop)
+ return JS_FALSE;
+ }
+ js_RemoveRoot(cx->runtime, &wp->closure);
+ JS_free(cx, wp);
+ return JS_TRUE;
+}
+
+void
+js_MarkWatchPoints(JSRuntime *rt)
+{
+ JSWatchPoint *wp;
+
+ for (wp = (JSWatchPoint *)rt->watchPointList.next;
+ wp != (JSWatchPoint *)&rt->watchPointList;
+ wp = (JSWatchPoint *)wp->links.next) {
+ MARK_SCOPE_PROPERTY(wp->sprop);
+ }
+}
+
+static JSWatchPoint *
+FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
+{
+ JSWatchPoint *wp;
+
+ for (wp = (JSWatchPoint *)rt->watchPointList.next;
+ wp != (JSWatchPoint *)&rt->watchPointList;
+ wp = (JSWatchPoint *)wp->links.next) {
+ if (wp->object == scope->object && wp->sprop->id == id)
+ return wp;
+ }
+ return NULL;
+}
+
+JSScopeProperty *
+js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
+{
+ JSWatchPoint *wp;
+
+ wp = FindWatchPoint(rt, scope, id);
+ if (!wp)
+ return NULL;
+ return wp->sprop;
+}
+
+JSPropertyOp
+js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
+ const JSScopeProperty *sprop)
+{
+ JSWatchPoint *wp;
+
+ for (wp = (JSWatchPoint *)rt->watchPointList.next;
+ wp != (JSWatchPoint *)&rt->watchPointList;
+ wp = (JSWatchPoint *)wp->links.next) {
+ if ((!scope || wp->object == scope->object) && wp->sprop == sprop)
+ return wp->setter;
+ }
+ return NULL;
+}
+
+JSBool JS_DLL_CALLBACK
+js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSRuntime *rt;
+ JSWatchPoint *wp;
+ JSScopeProperty *sprop;
+ jsval userid;
+ JSScope *scope;
+ JSBool ok;
+
+ rt = cx->runtime;
+ for (wp = (JSWatchPoint *)rt->watchPointList.next;
+ wp != (JSWatchPoint *)&rt->watchPointList;
+ wp = (JSWatchPoint *)wp->links.next) {
+ sprop = wp->sprop;
+ if (wp->object == obj && SPROP_USERID(sprop) == id) {
+ JS_LOCK_OBJ(cx, obj);
+ userid = SPROP_USERID(sprop);
+ scope = OBJ_SCOPE(obj);
+ JS_UNLOCK_OBJ(cx, obj);
+ HoldWatchPoint(wp);
+ ok = wp->handler(cx, obj, userid,
+ SPROP_HAS_VALID_SLOT(sprop, scope)
+ ? OBJ_GET_SLOT(cx, obj, wp->sprop->slot)
+ : JSVAL_VOID,
+ vp, wp->closure);
+ if (ok) {
+ /*
+ * Create pseudo-frame for call to setter so that any
+ * stack-walking security code in the setter will correctly
+ * identify the guilty party.
+ */
+ JSObject *funobj = (JSObject *) wp->closure;
+ JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, funobj);
+ JSStackFrame frame;
+
+ memset(&frame, 0, sizeof(frame));
+ frame.script = fun->script;
+ frame.fun = fun;
+ frame.down = cx->fp;
+ cx->fp = &frame;
+ ok = !wp->setter ||
+ ((sprop->attrs & JSPROP_SETTER)
+ ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
+ 1, vp, vp)
+ : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
+ cx->fp = frame.down;
+ }
+ return DropWatchPoint(cx, wp);
+ }
+ }
+ JS_ASSERT(0); /* XXX can't happen */
+ return JS_FALSE;
+}
+
+JSBool JS_DLL_CALLBACK
+js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSObject *funobj;
+ JSFunction *wrapper;
+ jsval userid;
+
+ funobj = JSVAL_TO_OBJECT(argv[-2]);
+ wrapper = (JSFunction *) JS_GetPrivate(cx, funobj);
+ userid = ATOM_KEY(wrapper->atom);
+ *rval = argv[0];
+ return js_watch_set(cx, obj, userid, rval);
+}
+
+JSPropertyOp
+js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
+{
+ JSAtom *atom;
+ JSFunction *wrapper;
+
+ if (!(attrs & JSPROP_SETTER))
+ return &js_watch_set; /* & to silence schoolmarmish MSVC */
+
+ if (!JSVAL_IS_INT(id)) {
+ atom = (JSAtom *)id;
+ } else {
+ atom = js_AtomizeInt(cx, JSVAL_TO_INT(id), 0);
+ if (!atom)
+ return NULL;
+ }
+ wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
+ OBJ_GET_PARENT(cx, (JSObject *)setter),
+ atom);
+ if (!wrapper)
+ return NULL;
+ return (JSPropertyOp) wrapper->object;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
+ JSWatchPointHandler handler, void *closure)
+{
+ JSAtom *atom;
+ jsid propid;
+ JSObject *pobj;
+ JSScopeProperty *sprop;
+ JSRuntime *rt;
+ JSWatchPoint *wp;
+ JSPropertyOp watcher;
+
+ if (!OBJ_IS_NATIVE(obj)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
+ OBJ_GET_CLASS(cx, obj)->name);
+ return JS_FALSE;
+ }
+
+ if (JSVAL_IS_INT(id)) {
+ propid = (jsid)id;
+ atom = NULL;
+ } else {
+ atom = js_ValueToStringAtom(cx, id);
+ if (!atom)
+ return JS_FALSE;
+ propid = (jsid)atom;
+ }
+
+ if (!js_LookupProperty(cx, obj, propid, &pobj, (JSProperty **)&sprop))
+ return JS_FALSE;
+ rt = cx->runtime;
+ if (!sprop) {
+ /* Check for a deleted symbol watchpoint, which holds its property. */
+ sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
+ if (!sprop) {
+ /* Make a new property in obj so we can watch for the first set. */
+ if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
+ NULL, NULL, JSPROP_ENUMERATE,
+ (JSProperty **)&sprop)) {
+ sprop = NULL;
+ }
+ }
+ } else if (pobj != obj) {
+ /* Clone the prototype property so we can watch the right object. */
+ jsval value;
+ JSPropertyOp getter, setter;
+ uintN attrs;
+
+ if (OBJ_IS_NATIVE(pobj)) {
+ value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
+ ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
+ : JSVAL_VOID;
+ getter = sprop->getter;
+ setter = sprop->setter;
+ attrs = sprop->attrs;
+ } else {
+ if (!OBJ_GET_PROPERTY(cx, pobj, id, &value)) {
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ return JS_FALSE;
+ }
+ getter = setter = JS_PropertyStub;
+ attrs = JSPROP_ENUMERATE;
+ }
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+
+ if (!js_DefineProperty(cx, obj, propid, value, getter, setter, attrs,
+ (JSProperty **)&sprop)) {
+ sprop = NULL;
+ }
+ }
+ if (!sprop)
+ return JS_FALSE;
+
+ wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
+ if (!wp) {
+ watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
+ if (!watcher)
+ return JS_FALSE;
+
+ wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
+ if (!wp)
+ return JS_FALSE;
+ wp->handler = NULL;
+ wp->closure = NULL;
+ if (!js_AddRoot(cx, &wp->closure, "wp->closure")) {
+ JS_free(cx, wp);
+ return JS_FALSE;
+ }
+ JS_APPEND_LINK(&wp->links, &rt->watchPointList);
+ wp->object = obj;
+ wp->sprop = sprop;
+ JS_ASSERT(sprop->setter != js_watch_set);
+ wp->setter = sprop->setter;
+ wp->nrefs = 1;
+ sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
+ sprop->getter, watcher);
+ if (!sprop)
+ return DropWatchPoint(cx, wp);
+ }
+ wp->handler = handler;
+ wp->closure = closure;
+ OBJ_DROP_PROPERTY(cx, obj, (JSProperty *)sprop);
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
+ JSWatchPointHandler *handlerp, void **closurep)
+{
+ JSRuntime *rt;
+ JSWatchPoint *wp;
+
+ rt = cx->runtime;
+ for (wp = (JSWatchPoint *)rt->watchPointList.next;
+ wp != (JSWatchPoint *)&rt->watchPointList;
+ wp = (JSWatchPoint *)wp->links.next) {
+ if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
+ if (handlerp)
+ *handlerp = wp->handler;
+ if (closurep)
+ *closurep = wp->closure;
+ return DropWatchPoint(cx, wp);
+ }
+ }
+ if (handlerp)
+ *handlerp = NULL;
+ if (closurep)
+ *closurep = NULL;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
+{
+ JSRuntime *rt;
+ JSWatchPoint *wp, *next;
+
+ rt = cx->runtime;
+ for (wp = (JSWatchPoint *)rt->watchPointList.next;
+ wp != (JSWatchPoint *)&rt->watchPointList;
+ wp = next) {
+ next = (JSWatchPoint *)wp->links.next;
+ if (wp->object == obj && !DropWatchPoint(cx, wp))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ClearAllWatchPoints(JSContext *cx)
+{
+ JSRuntime *rt;
+ JSWatchPoint *wp, *next;
+
+ rt = cx->runtime;
+ for (wp = (JSWatchPoint *)rt->watchPointList.next;
+ wp != (JSWatchPoint *)&rt->watchPointList;
+ wp = next) {
+ next = (JSWatchPoint *)wp->links.next;
+ if (!DropWatchPoint(cx, wp))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(uintN)
+JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
+{
+ return js_PCToLineNumber(cx, script, pc);
+}
+
+JS_PUBLIC_API(jsbytecode *)
+JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
+{
+ return js_LineNumberToPC(script, lineno);
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
+{
+ return fun->script;
+}
+
+JS_PUBLIC_API(JSPrincipals *)
+JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
+{
+ return script->principals;
+}
+
+/************************************************************************/
+
+/*
+ * Stack Frame Iterator
+ */
+JS_PUBLIC_API(JSStackFrame *)
+JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
+{
+ *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
+ return *iteratorp;
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
+{
+ return fp->script;
+}
+
+JS_PUBLIC_API(jsbytecode *)
+JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
+{
+ return fp->pc;
+}
+
+JS_PUBLIC_API(JSStackFrame *)
+JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
+{
+ if (!fp)
+ fp = cx->fp;
+ while ((fp = fp->down) != NULL) {
+ if (fp->script)
+ return fp;
+ }
+ return NULL;
+}
+
+JS_PUBLIC_API(JSPrincipals *)
+JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
+{
+ if (fp->fun && cx->findObjectPrincipals) {
+ JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]);
+
+ if (fp->fun->object != callee)
+ return cx->findObjectPrincipals(cx, callee);
+ /* FALL THROUGH */
+ }
+ if (fp->script)
+ return fp->script->principals;
+ return NULL;
+}
+
+JS_PUBLIC_API(JSPrincipals *)
+JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
+{
+ if (cx->findObjectPrincipals)
+ return cx->findObjectPrincipals(cx, JSVAL_TO_OBJECT(fp->argv[-2]));
+ if (!caller)
+ return NULL;
+ return JS_StackFramePrincipals(cx, caller);
+}
+
+JS_PUBLIC_API(void *)
+JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
+{
+ if (fp->annotation && fp->script) {
+ JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
+
+ if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
+ /*
+ * Give out an annotation only if privileges have not been revoked
+ * or disabled globally.
+ */
+ return fp->annotation;
+ }
+ }
+
+ return NULL;
+}
+
+JS_PUBLIC_API(void)
+JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
+{
+ fp->annotation = annotation;
+}
+
+JS_PUBLIC_API(void *)
+JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
+{
+ JSPrincipals *principals;
+
+ principals = JS_StackFramePrincipals(cx, fp);
+ if (!principals)
+ return NULL;
+ return principals->getPrincipalArray(cx, principals);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
+{
+ return !fp->script;
+}
+
+/* this is deprecated, use JS_GetFrameScopeChain instead */
+JS_PUBLIC_API(JSObject *)
+JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
+{
+ return fp->scopeChain;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
+{
+ /* Force creation of argument and call objects if not yet created */
+ (void) JS_GetFrameCallObject(cx, fp);
+ return fp->scopeChain;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
+{
+ if (! fp->fun)
+ return NULL;
+#if JS_HAS_ARGS_OBJECT
+ /* Force creation of argument object if not yet created */
+ (void) js_GetArgsObject(cx, fp);
+#endif
+#if JS_HAS_CALL_OBJECT
+ /*
+ * XXX ill-defined: null return here means error was reported, unlike a
+ * null returned above or in the #else
+ */
+ return js_GetCallObject(cx, fp, NULL);
+#else
+ return NULL;
+#endif /* JS_HAS_CALL_OBJECT */
+}
+
+
+JS_PUBLIC_API(JSObject *)
+JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
+{
+ return fp->thisp;
+}
+
+JS_PUBLIC_API(JSFunction *)
+JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
+{
+ return fp->fun;
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
+{
+ return fp->argv && fp->fun ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
+{
+ return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
+{
+ return (fp->flags & JSFRAME_DEBUGGER) != 0;
+}
+
+JS_PUBLIC_API(jsval)
+JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
+{
+ return fp->rval;
+}
+
+JS_PUBLIC_API(void)
+JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
+{
+ fp->rval = rval;
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(const char *)
+JS_GetScriptFilename(JSContext *cx, JSScript *script)
+{
+ return script->filename;
+}
+
+JS_PUBLIC_API(uintN)
+JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
+{
+ return script->lineno;
+}
+
+JS_PUBLIC_API(uintN)
+JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
+{
+ return js_GetScriptLineExtent(script);
+}
+
+JS_PUBLIC_API(JSVersion)
+JS_GetScriptVersion(JSContext *cx, JSScript *script)
+{
+ return script->version;
+}
+
+/***************************************************************************/
+
+JS_PUBLIC_API(void)
+JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
+{
+ rt->newScriptHook = hook;
+ rt->newScriptHookData = callerdata;
+}
+
+JS_PUBLIC_API(void)
+JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
+ void *callerdata)
+{
+ rt->destroyScriptHook = hook;
+ rt->destroyScriptHookData = callerdata;
+}
+
+/***************************************************************************/
+
+JS_PUBLIC_API(JSBool)
+JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
+ const jschar *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+{
+ uint32 flags;
+ JSScript *script;
+ JSBool ok;
+
+ /*
+ * XXX Hack around ancient compiler API to propagate the JSFRAME_SPECIAL
+ * flags to the code generator (see js_EmitTree's TOK_SEMI case).
+ */
+ flags = fp->flags;
+ fp->flags |= JSFRAME_DEBUGGER | JSFRAME_EVAL;
+ script = JS_CompileUCScriptForPrincipals(cx, fp->scopeChain,
+ JS_StackFramePrincipals(cx, fp),
+ bytes, length, filename, lineno);
+ fp->flags = flags;
+ if (!script)
+ return JS_FALSE;
+
+ ok = js_Execute(cx, fp->scopeChain, script, fp,
+ JSFRAME_DEBUGGER | JSFRAME_EVAL, rval);
+ js_DestroyScript(cx, script);
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+{
+ jschar *chars;
+ JSBool ok;
+
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return JS_FALSE;
+ ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
+ rval);
+ JS_free(cx, chars);
+
+ return ok;
+}
+
+/************************************************************************/
+
+/* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
+
+JS_PUBLIC_API(JSScopeProperty *)
+JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
+{
+ JSScopeProperty *sprop;
+ JSScope *scope;
+
+ sprop = *iteratorp;
+ scope = OBJ_SCOPE(obj);
+
+ /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
+ if (!sprop) {
+ sprop = SCOPE_LAST_PROP(scope);
+ } else {
+ while ((sprop = sprop->parent) != NULL) {
+ if (!SCOPE_HAD_MIDDLE_DELETE(scope))
+ break;
+ if (SCOPE_HAS_PROPERTY(scope, sprop))
+ break;
+ }
+ }
+ *iteratorp = sprop;
+ return sprop;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
+ JSPropertyDesc *pd)
+{
+ JSPropertyOp getter;
+ JSScope *scope;
+ JSScopeProperty *aprop;
+ jsval lastException;
+ JSBool wasThrowing;
+
+ pd->id = ID_TO_VALUE(sprop->id);
+
+ wasThrowing = cx->throwing;
+ if (wasThrowing) {
+ lastException = cx->exception;
+ if (JSVAL_IS_GCTHING(lastException) &&
+ !js_AddRoot(cx, &lastException, "lastException")) {
+ return JS_FALSE;
+ }
+ cx->throwing = JS_FALSE;
+ }
+
+ if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
+ if (!cx->throwing) {
+ pd->flags = JSPD_ERROR;
+ pd->value = JSVAL_VOID;
+ } else {
+ pd->flags = JSPD_EXCEPTION;
+ pd->value = cx->exception;
+ }
+ } else {
+ pd->flags = 0;
+ }
+
+ cx->throwing = wasThrowing;
+ if (wasThrowing) {
+ cx->exception = lastException;
+ if (JSVAL_IS_GCTHING(lastException))
+ js_RemoveRoot(cx->runtime, &lastException);
+ }
+
+ getter = sprop->getter;
+ pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
+ | ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0)
+ | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0)
+#if JS_HAS_CALL_OBJECT
+ | ((getter == js_GetCallVariable) ? JSPD_VARIABLE : 0)
+#endif /* JS_HAS_CALL_OBJECT */
+ | ((getter == js_GetArgument) ? JSPD_ARGUMENT : 0)
+ | ((getter == js_GetLocalVariable) ? JSPD_VARIABLE : 0);
+#if JS_HAS_CALL_OBJECT
+ /* for Call Object 'real' getter isn't passed in to us */
+ if (OBJ_GET_CLASS(cx, obj) == &js_CallClass &&
+ getter == js_CallClass.getProperty) {
+ /*
+ * Property of a heavyweight function's variable object having the
+ * class-default getter. It's either an argument if permanent, or a
+ * nested function if impermanent. Local variables have a special
+ * getter (js_GetCallVariable, tested above) and setter, and not the
+ * class default.
+ */
+ pd->flags |= (sprop->attrs & JSPROP_PERMANENT)
+ ? JSPD_ARGUMENT
+ : JSPD_VARIABLE;
+ }
+#endif /* JS_HAS_CALL_OBJECT */
+ pd->spare = 0;
+ pd->slot = (pd->flags & (JSPD_ARGUMENT | JSPD_VARIABLE))
+ ? sprop->shortid
+ : 0;
+ pd->alias = JSVAL_VOID;
+ scope = OBJ_SCOPE(obj);
+ if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
+ for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
+ if (aprop != sprop && aprop->slot == sprop->slot) {
+ pd->alias = ID_TO_VALUE(aprop->id);
+ break;
+ }
+ }
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
+{
+ JSClass *clasp;
+ JSScope *scope;
+ uint32 i, n;
+ JSPropertyDesc *pd;
+ JSScopeProperty *sprop;
+
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
+ return JS_FALSE;
+ }
+ if (!clasp->enumerate(cx, obj))
+ return JS_FALSE;
+
+ /* have no props, or object's scope has not mutated from that of proto */
+ scope = OBJ_SCOPE(obj);
+ if (scope->object != obj || scope->entryCount == 0) {
+ pda->length = 0;
+ pda->array = NULL;
+ return JS_TRUE;
+ }
+
+ n = scope->entryCount;
+ if (n > scope->map.nslots)
+ n = scope->map.nslots;
+ pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
+ if (!pd)
+ return JS_FALSE;
+ i = 0;
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
+ continue;
+ if (!js_AddRoot(cx, &pd[i].id, NULL))
+ goto bad;
+ if (!js_AddRoot(cx, &pd[i].value, NULL))
+ goto bad;
+ if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
+ goto bad;
+ if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
+ goto bad;
+ if (++i == n)
+ break;
+ }
+ pda->length = i;
+ pda->array = pd;
+ return JS_TRUE;
+
+bad:
+ pda->length = i + 1;
+ pda->array = pd;
+ JS_PutPropertyDescArray(cx, pda);
+ return JS_FALSE;
+}
+
+JS_PUBLIC_API(void)
+JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
+{
+ JSPropertyDesc *pd;
+ uint32 i;
+
+ pd = pda->array;
+ for (i = 0; i < pda->length; i++) {
+ js_RemoveRoot(cx->runtime, &pd[i].id);
+ js_RemoveRoot(cx->runtime, &pd[i].value);
+ if (pd[i].flags & JSPD_ALIAS)
+ js_RemoveRoot(cx->runtime, &pd[i].alias);
+ }
+ JS_free(cx, pd);
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(JSBool)
+JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
+{
+ rt->debuggerHandler = handler;
+ rt->debuggerHandlerData = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
+{
+ rt->sourceHandler = handler;
+ rt->sourceHandlerData = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
+{
+ rt->executeHook = hook;
+ rt->executeHookData = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
+{
+ rt->callHook = hook;
+ rt->callHookData = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
+{
+ rt->objectHook = hook;
+ rt->objectHookData = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
+{
+ rt->throwHook = hook;
+ rt->throwHookData = closure;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
+{
+ rt->debugErrorHook = hook;
+ rt->debugErrorHookData = closure;
+ return JS_TRUE;
+}
+
+/************************************************************************/
+
+JS_PUBLIC_API(size_t)
+JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
+{
+ size_t nbytes;
+ JSScope *scope;
+
+ nbytes = sizeof *obj + obj->map->nslots * sizeof obj->slots[0];
+ if (OBJ_IS_NATIVE(obj)) {
+ scope = OBJ_SCOPE(obj);
+ if (scope->object == obj) {
+ nbytes += sizeof *scope;
+ nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
+ }
+ }
+ return nbytes;
+}
+
+static size_t
+GetAtomTotalSize(JSContext *cx, JSAtom *atom)
+{
+ size_t nbytes;
+
+ nbytes = sizeof *atom;
+ if (ATOM_IS_STRING(atom)) {
+ nbytes += sizeof(JSString);
+ nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);
+ } else if (ATOM_IS_DOUBLE(atom)) {
+ nbytes += sizeof(jsdouble);
+ } else if (ATOM_IS_OBJECT(atom)) {
+ nbytes += JS_GetObjectTotalSize(cx, ATOM_TO_OBJECT(atom));
+ }
+ return nbytes;
+}
+
+JS_PUBLIC_API(size_t)
+JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
+{
+ size_t nbytes, obytes;
+ JSObject *obj;
+ JSAtom *atom;
+
+ nbytes = sizeof *fun;
+ JS_ASSERT(fun->nrefs);
+ obj = fun->object;
+ if (obj) {
+ obytes = JS_GetObjectTotalSize(cx, obj);
+ if (fun->nrefs > 1)
+ obytes = JS_HOWMANY(obytes, fun->nrefs);
+ nbytes += obytes;
+ }
+ if (fun->script)
+ nbytes += JS_GetScriptTotalSize(cx, fun->script);
+ atom = fun->atom;
+ if (atom)
+ nbytes += GetAtomTotalSize(cx, atom);
+ return nbytes;
+}
+
+#include "jsemit.h"
+
+JS_PUBLIC_API(size_t)
+JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
+{
+ size_t nbytes, pbytes;
+ JSObject *obj;
+ jsatomid i;
+ jssrcnote *sn, *notes;
+ JSTryNote *tn, *tnotes;
+ JSPrincipals *principals;
+
+ nbytes = sizeof *script;
+ obj = script->object;
+ if (obj)
+ nbytes += JS_GetObjectTotalSize(cx, obj);
+
+ nbytes += script->length * sizeof script->code[0];
+ nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
+ for (i = 0; i < script->atomMap.length; i++)
+ nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
+
+ if (script->filename)
+ nbytes += strlen(script->filename) + 1;
+
+ notes = SCRIPT_NOTES(script);
+ for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
+ continue;
+ nbytes += (sn - notes + 1) * sizeof *sn;
+
+ tnotes = script->trynotes;
+ if (tnotes) {
+ for (tn = tnotes; tn->catchStart; tn++)
+ continue;
+ nbytes += (tn - tnotes + 1) * sizeof *tn;
+ }
+
+ principals = script->principals;
+ if (principals) {
+ JS_ASSERT(principals->refcount);
+ pbytes = sizeof *principals;
+ if (principals->refcount > 1)
+ pbytes = JS_HOWMANY(pbytes, principals->refcount);
+ nbytes += pbytes;
+ }
+
+ return nbytes;
+}
diff --git a/src/dom/js/jsdbgapi.h b/src/dom/js/jsdbgapi.h
new file mode 100644
index 000000000..90215a275
--- /dev/null
+++ b/src/dom/js/jsdbgapi.h
@@ -0,0 +1,345 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsdbgapi_h___
+#define jsdbgapi_h___
+/*
+ * JS debugger API.
+ */
+#include "jsapi.h"
+#include "jsopcode.h"
+#include "jsprvtd.h"
+
+JS_BEGIN_EXTERN_C
+
+extern void
+js_PatchOpcode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
+ JSTrapHandler handler, void *closure);
+
+extern JS_PUBLIC_API(JSOp)
+JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc);
+
+extern JS_PUBLIC_API(void)
+JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
+ JSTrapHandler *handlerp, void **closurep);
+
+extern JS_PUBLIC_API(void)
+JS_ClearScriptTraps(JSContext *cx, JSScript *script);
+
+extern JS_PUBLIC_API(void)
+JS_ClearAllTraps(JSContext *cx);
+
+extern JS_PUBLIC_API(JSTrapStatus)
+JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep);
+
+/************************************************************************/
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
+ JSWatchPointHandler handler, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
+ JSWatchPointHandler *handlerp, void **closurep);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(JSBool)
+JS_ClearAllWatchPoints(JSContext *cx);
+
+#ifdef JS_HAS_OBJ_WATCHPOINT
+/*
+ * Hide these non-API function prototypes by testing whether the internal
+ * header file "jsconfig.h" has been included.
+ */
+extern void
+js_MarkWatchPoints(JSRuntime *rt);
+
+extern JSScopeProperty *
+js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id);
+
+extern JSPropertyOp
+js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
+ const JSScopeProperty *sprop);
+
+extern JSBool JS_DLL_CALLBACK
+js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+extern JSBool JS_DLL_CALLBACK
+js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+extern JSPropertyOp
+js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter);
+
+#endif /* JS_HAS_OBJ_WATCHPOINT */
+
+/************************************************************************/
+
+extern JS_PUBLIC_API(uintN)
+JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
+
+extern JS_PUBLIC_API(jsbytecode *)
+JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_GetFunctionScript(JSContext *cx, JSFunction *fun);
+
+extern JS_PUBLIC_API(JSPrincipals *)
+JS_GetScriptPrincipals(JSContext *cx, JSScript *script);
+
+/*
+ * Stack Frame Iterator
+ *
+ * Used to iterate through the JS stack frames to extract
+ * information from the frames.
+ */
+
+extern JS_PUBLIC_API(JSStackFrame *)
+JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_GetFrameScript(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(jsbytecode *)
+JS_GetFramePC(JSContext *cx, JSStackFrame *fp);
+
+/*
+ * Get the closest scripted frame below fp. If fp is null, start from cx->fp.
+ */
+extern JS_PUBLIC_API(JSStackFrame *)
+JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp);
+
+/*
+ * Return a weak reference to fp's principals. A null return does not denote
+ * an error, it means there are no principals.
+ */
+extern JS_PUBLIC_API(JSPrincipals *)
+JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp);
+
+/*
+ * Like JS_StackFramePrincipals(cx, caller), but if cx->findObjectPrincipals
+ * is non-null, return the object principals for fp's callee function object
+ * (fp->argv[-2]), which is eval, Function, or a similar eval-like method.
+ * The caller parameter should be the result of JS_GetScriptedCaller(cx, fp).
+ *
+ * All eval-like methods must use JS_EvalFramePrincipals to acquire a weak
+ * reference to the correct principals for the eval call to be secure, given
+ * an embedding that calls JS_SetObjectPrincipalsFinder (see jsapi.h).
+ */
+extern JS_PUBLIC_API(JSPrincipals *)
+JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller);
+
+extern JS_PUBLIC_API(void *)
+JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(void)
+JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation);
+
+extern JS_PUBLIC_API(void *)
+JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp);
+
+/* this is deprecated, use JS_GetFrameScopeChain instead */
+extern JS_PUBLIC_API(JSObject *)
+JS_GetFrameObject(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetFrameThis(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(JSFunction *)
+JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(JSObject *)
+JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp);
+
+/* XXXrginda Initially published with typo */
+#define JS_IsContructorFrame JS_IsConstructorFrame
+extern JS_PUBLIC_API(JSBool)
+JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(jsval)
+JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp);
+
+extern JS_PUBLIC_API(void)
+JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval);
+
+/************************************************************************/
+
+extern JS_PUBLIC_API(const char *)
+JS_GetScriptFilename(JSContext *cx, JSScript *script);
+
+extern JS_PUBLIC_API(uintN)
+JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);
+
+extern JS_PUBLIC_API(uintN)
+JS_GetScriptLineExtent(JSContext *cx, JSScript *script);
+
+extern JS_PUBLIC_API(JSVersion)
+JS_GetScriptVersion(JSContext *cx, JSScript *script);
+
+/************************************************************************/
+
+/*
+ * Hook setters for script creation and destruction, see jsprvtd.h for the
+ * typedefs. These macros provide binary compatibility and newer, shorter
+ * synonyms.
+ */
+#define JS_SetNewScriptHook JS_SetNewScriptHookProc
+#define JS_SetDestroyScriptHook JS_SetDestroyScriptHookProc
+
+extern JS_PUBLIC_API(void)
+JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata);
+
+extern JS_PUBLIC_API(void)
+JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
+ void *callerdata);
+
+/************************************************************************/
+
+extern JS_PUBLIC_API(JSBool)
+JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
+ const jschar *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval);
+
+extern JS_PUBLIC_API(JSBool)
+JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval);
+
+/************************************************************************/
+
+typedef struct JSPropertyDesc {
+ jsval id; /* primary id, a string or int */
+ jsval value; /* property value */
+ uint8 flags; /* flags, see below */
+ uint8 spare; /* unused */
+ uint16 slot; /* argument/variable slot */
+ jsval alias; /* alias id if JSPD_ALIAS flag */
+} JSPropertyDesc;
+
+#define JSPD_ENUMERATE 0x01 /* visible to for/in loop */
+#define JSPD_READONLY 0x02 /* assignment is error */
+#define JSPD_PERMANENT 0x04 /* property cannot be deleted */
+#define JSPD_ALIAS 0x08 /* property has an alias id */
+#define JSPD_ARGUMENT 0x10 /* argument to function */
+#define JSPD_VARIABLE 0x20 /* local variable in function */
+#define JSPD_EXCEPTION 0x40 /* exception occurred fetching the property, */
+ /* value is exception */
+#define JSPD_ERROR 0x80 /* native getter returned JS_FALSE without */
+ /* throwing an exception */
+
+typedef struct JSPropertyDescArray {
+ uint32 length; /* number of elements in array */
+ JSPropertyDesc *array; /* alloc'd by Get, freed by Put */
+} JSPropertyDescArray;
+
+extern JS_PUBLIC_API(JSScopeProperty *)
+JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
+ JSPropertyDesc *pd);
+
+extern JS_PUBLIC_API(JSBool)
+JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda);
+
+extern JS_PUBLIC_API(void)
+JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda);
+
+/************************************************************************/
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure);
+
+extern JS_PUBLIC_API(JSBool)
+JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure);
+
+/************************************************************************/
+
+extern JS_PUBLIC_API(size_t)
+JS_GetObjectTotalSize(JSContext *cx, JSObject *obj);
+
+extern JS_PUBLIC_API(size_t)
+JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun);
+
+extern JS_PUBLIC_API(size_t)
+JS_GetScriptTotalSize(JSContext *cx, JSScript *script);
+
+JS_END_EXTERN_C
+
+#endif /* jsdbgapi_h___ */
diff --git a/src/dom/js/jsdhash.c b/src/dom/js/jsdhash.c
new file mode 100644
index 000000000..736de04ad
--- /dev/null
+++ b/src/dom/js/jsdhash.c
@@ -0,0 +1,763 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla JavaScript code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brendan Eich <brendan@mozilla.org> (Original Author)
+ * Chris Waterson <waterson@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Double hashing implementation.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jsbit.h"
+#include "jsdhash.h"
+#include "jsutil.h" /* for JS_ASSERT */
+
+#ifdef JS_DHASHMETER
+# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan
+# include "nsTraceMalloc.h"
+# endif
+# define METER(x) x
+#else
+# define METER(x) /* nothing */
+#endif
+
+JS_PUBLIC_API(void *)
+JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes)
+{
+ return malloc(nbytes);
+}
+
+JS_PUBLIC_API(void)
+JS_DHashFreeTable(JSDHashTable *table, void *ptr)
+{
+ free(ptr);
+}
+
+JS_PUBLIC_API(JSDHashNumber)
+JS_DHashStringKey(JSDHashTable *table, const void *key)
+{
+ JSDHashNumber h;
+ const unsigned char *s;
+
+ h = 0;
+ for (s = key; *s != '\0'; s++)
+ h = (h >> (JS_DHASH_BITS - 4)) ^ (h << 4) ^ *s;
+ return h;
+}
+
+JS_PUBLIC_API(const void *)
+JS_DHashGetKeyStub(JSDHashTable *table, JSDHashEntryHdr *entry)
+{
+ JSDHashEntryStub *stub = (JSDHashEntryStub *)entry;
+
+ return stub->key;
+}
+
+JS_PUBLIC_API(JSDHashNumber)
+JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key)
+{
+ return (JSDHashNumber)key >> 2;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DHashMatchEntryStub(JSDHashTable *table,
+ const JSDHashEntryHdr *entry,
+ const void *key)
+{
+ const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;
+
+ return stub->key == key;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DHashMatchStringKey(JSDHashTable *table,
+ const JSDHashEntryHdr *entry,
+ const void *key)
+{
+ const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;
+
+ /* XXX tolerate null keys on account of sloppy Mozilla callers. */
+ return stub->key == key ||
+ (stub->key && key && strcmp(stub->key, key) == 0);
+}
+
+JS_PUBLIC_API(void)
+JS_DHashMoveEntryStub(JSDHashTable *table,
+ const JSDHashEntryHdr *from,
+ JSDHashEntryHdr *to)
+{
+ memcpy(to, from, table->entrySize);
+}
+
+JS_PUBLIC_API(void)
+JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry)
+{
+ memset(entry, 0, table->entrySize);
+}
+
+JS_PUBLIC_API(void)
+JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry)
+{
+ const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;
+
+ free((void *) stub->key);
+ memset(entry, 0, table->entrySize);
+}
+
+JS_PUBLIC_API(void)
+JS_DHashFinalizeStub(JSDHashTable *table)
+{
+}
+
+static const JSDHashTableOps stub_ops = {
+ JS_DHashAllocTable,
+ JS_DHashFreeTable,
+ JS_DHashGetKeyStub,
+ JS_DHashVoidPtrKeyStub,
+ JS_DHashMatchEntryStub,
+ JS_DHashMoveEntryStub,
+ JS_DHashClearEntryStub,
+ JS_DHashFinalizeStub,
+ NULL
+};
+
+JS_PUBLIC_API(const JSDHashTableOps *)
+JS_DHashGetStubOps(void)
+{
+ return &stub_ops;
+}
+
+JS_PUBLIC_API(JSDHashTable *)
+JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize,
+ uint32 capacity)
+{
+ JSDHashTable *table;
+
+ table = (JSDHashTable *) malloc(sizeof *table);
+ if (!table)
+ return NULL;
+ if (!JS_DHashTableInit(table, ops, data, entrySize, capacity)) {
+ free(table);
+ return NULL;
+ }
+ return table;
+}
+
+JS_PUBLIC_API(void)
+JS_DHashTableDestroy(JSDHashTable *table)
+{
+ JS_DHashTableFinish(table);
+ free(table);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data,
+ uint32 entrySize, uint32 capacity)
+{
+ int log2;
+ uint32 nbytes;
+
+#ifdef DEBUG
+ if (entrySize > 10 * sizeof(void *)) {
+ fprintf(stderr,
+ "jsdhash: for the table at address %p, the given entrySize"
+ " of %lu %s favors chaining over double hashing.\n",
+ (void *)table,
+ (unsigned long) entrySize,
+ (entrySize > 16 * sizeof(void*)) ? "definitely" : "probably");
+ }
+#endif
+
+ table->ops = ops;
+ table->data = data;
+ if (capacity < JS_DHASH_MIN_SIZE)
+ capacity = JS_DHASH_MIN_SIZE;
+ log2 = JS_CeilingLog2(capacity);
+ capacity = JS_BIT(log2);
+ if (capacity >= JS_DHASH_SIZE_LIMIT)
+ return JS_FALSE;
+ table->hashShift = JS_DHASH_BITS - log2;
+ table->maxAlphaFrac = 0xC0; /* .75 */
+ table->minAlphaFrac = 0x40; /* .25 */
+ table->entrySize = entrySize;
+ table->entryCount = table->removedCount = 0;
+ table->generation = 0;
+ nbytes = capacity * entrySize;
+
+ table->entryStore = ops->allocTable(table, nbytes);
+ if (!table->entryStore)
+ return JS_FALSE;
+ memset(table->entryStore, 0, nbytes);
+ METER(memset(&table->stats, 0, sizeof table->stats));
+ return JS_TRUE;
+}
+
+/*
+ * Compute max and min load numbers (entry counts) from table params.
+ */
+#define MAX_LOAD(table, size) (((table)->maxAlphaFrac * (size)) >> 8)
+#define MIN_LOAD(table, size) (((table)->minAlphaFrac * (size)) >> 8)
+
+JS_PUBLIC_API(void)
+JS_DHashTableSetAlphaBounds(JSDHashTable *table,
+ float maxAlpha,
+ float minAlpha)
+{
+ uint32 size;
+
+ /*
+ * Reject obviously insane bounds, rather than trying to guess what the
+ * buggy caller intended.
+ */
+ JS_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha);
+ if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0)
+ return;
+
+ /*
+ * Ensure that at least one entry will always be free. If maxAlpha at
+ * minimum size leaves no entries free, reduce maxAlpha based on minimum
+ * size and the precision limit of maxAlphaFrac's fixed point format.
+ */
+ JS_ASSERT(JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) >= 1);
+ if (JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) < 1) {
+ maxAlpha = (float)
+ (JS_DHASH_MIN_SIZE - JS_MAX(JS_DHASH_MIN_SIZE / 256, 1))
+ / JS_DHASH_MIN_SIZE;
+ }
+
+ /*
+ * Ensure that minAlpha is strictly less than half maxAlpha. Take care
+ * not to truncate an entry's worth of alpha when storing in minAlphaFrac
+ * (8-bit fixed point format).
+ */
+ JS_ASSERT(minAlpha < maxAlpha / 2);
+ if (minAlpha >= maxAlpha / 2) {
+ size = JS_DHASH_TABLE_SIZE(table);
+ minAlpha = (size * maxAlpha - JS_MAX(size / 256, 1)) / (2 * size);
+ }
+
+ table->maxAlphaFrac = (uint8)(maxAlpha * 256);
+ table->minAlphaFrac = (uint8)(minAlpha * 256);
+}
+
+/*
+ * Double hashing needs the second hash code to be relatively prime to table
+ * size, so we simply make hash2 odd.
+ */
+#define HASH1(hash0, shift) ((hash0) >> (shift))
+#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1)
+
+/*
+ * Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. Note
+ * that a removed-entry sentinel need be stored only if the removed entry had
+ * a colliding entry added after it. Therefore we can use 1 as the collision
+ * flag in addition to the removed-entry sentinel value. Multiplicative hash
+ * uses the high order bits of keyHash, so this least-significant reservation
+ * should not hurt the hash function's effectiveness much.
+ *
+ * If you change any of these magic numbers, also update JS_DHASH_ENTRY_IS_LIVE
+ * in jsdhash.h. It used to be private to jsdhash.c, but then became public to
+ * assist iterator writers who inspect table->entryStore directly.
+ */
+#define COLLISION_FLAG ((JSDHashNumber) 1)
+#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0)
+#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1)
+#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1)
+#define ENTRY_IS_LIVE(entry) JS_DHASH_ENTRY_IS_LIVE(entry)
+#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0
+
+/* Match an entry's keyHash against an unstored one computed from a key. */
+#define MATCH_ENTRY_KEYHASH(entry,hash0) \
+ (((entry)->keyHash & ~COLLISION_FLAG) == (hash0))
+
+/* Compute the address of the indexed entry in table. */
+#define ADDRESS_ENTRY(table, index) \
+ ((JSDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize))
+
+JS_PUBLIC_API(void)
+JS_DHashTableFinish(JSDHashTable *table)
+{
+ char *entryAddr, *entryLimit;
+ uint32 entrySize;
+ JSDHashEntryHdr *entry;
+
+#ifdef DEBUG_XXXbrendan
+ static FILE *dumpfp = NULL;
+ if (!dumpfp) dumpfp = fopen("/tmp/jsdhash.bigdump", "w");
+ if (dumpfp) {
+#ifdef MOZILLA_CLIENT
+ NS_TraceStack(1, dumpfp);
+#endif
+ JS_DHashTableDumpMeter(table, NULL, dumpfp);
+ fputc('\n', dumpfp);
+ }
+#endif
+
+ /* Call finalize before clearing entries, so it can enumerate them. */
+ table->ops->finalize(table);
+
+ /* Clear any remaining live entries. */
+ entryAddr = table->entryStore;
+ entrySize = table->entrySize;
+ entryLimit = entryAddr + JS_DHASH_TABLE_SIZE(table) * entrySize;
+ while (entryAddr < entryLimit) {
+ entry = (JSDHashEntryHdr *)entryAddr;
+ if (ENTRY_IS_LIVE(entry)) {
+ METER(table->stats.removeEnums++);
+ table->ops->clearEntry(table, entry);
+ }
+ entryAddr += entrySize;
+ }
+
+ /* Free entry storage last. */
+ table->ops->freeTable(table, table->entryStore);
+}
+
+static JSDHashEntryHdr *
+SearchTable(JSDHashTable *table, const void *key, JSDHashNumber keyHash,
+ JSDHashOperator op)
+{
+ JSDHashNumber hash1, hash2;
+ int hashShift, sizeLog2;
+ JSDHashEntryHdr *entry, *firstRemoved;
+ JSDHashMatchEntry matchEntry;
+ uint32 sizeMask;
+
+ METER(table->stats.searches++);
+ JS_ASSERT(!(keyHash & COLLISION_FLAG));
+
+ /* Compute the primary hash address. */
+ hashShift = table->hashShift;
+ hash1 = HASH1(keyHash, hashShift);
+ entry = ADDRESS_ENTRY(table, hash1);
+
+ /* Miss: return space for a new entry. */
+ if (JS_DHASH_ENTRY_IS_FREE(entry)) {
+ METER(table->stats.misses++);
+ return entry;
+ }
+
+ /* Hit: return entry. */
+ matchEntry = table->ops->matchEntry;
+ if (MATCH_ENTRY_KEYHASH(entry, keyHash) && matchEntry(table, entry, key)) {
+ METER(table->stats.hits++);
+ return entry;
+ }
+
+ /* Collision: double hash. */
+ sizeLog2 = JS_DHASH_BITS - table->hashShift;
+ hash2 = HASH2(keyHash, sizeLog2, hashShift);
+ sizeMask = JS_BITMASK(sizeLog2);
+
+ /* Save the first removed entry pointer so JS_DHASH_ADD can recycle it. */
+ if (ENTRY_IS_REMOVED(entry)) {
+ firstRemoved = entry;
+ } else {
+ firstRemoved = NULL;
+ if (op == JS_DHASH_ADD)
+ entry->keyHash |= COLLISION_FLAG;
+ }
+
+ for (;;) {
+ METER(table->stats.steps++);
+ hash1 -= hash2;
+ hash1 &= sizeMask;
+
+ entry = ADDRESS_ENTRY(table, hash1);
+ if (JS_DHASH_ENTRY_IS_FREE(entry)) {
+ METER(table->stats.misses++);
+ return (firstRemoved && op == JS_DHASH_ADD) ? firstRemoved : entry;
+ }
+
+ if (MATCH_ENTRY_KEYHASH(entry, keyHash) &&
+ matchEntry(table, entry, key)) {
+ METER(table->stats.hits++);
+ return entry;
+ }
+
+ if (ENTRY_IS_REMOVED(entry)) {
+ if (!firstRemoved)
+ firstRemoved = entry;
+ } else {
+ if (op == JS_DHASH_ADD)
+ entry->keyHash |= COLLISION_FLAG;
+ }
+ }
+
+ /* NOTREACHED */
+ return NULL;
+}
+
+static JSBool
+ChangeTable(JSDHashTable *table, int deltaLog2)
+{
+ int oldLog2, newLog2;
+ uint32 oldCapacity, newCapacity;
+ char *newEntryStore, *oldEntryStore, *oldEntryAddr;
+ uint32 entrySize, i, nbytes;
+ JSDHashEntryHdr *oldEntry, *newEntry;
+ JSDHashGetKey getKey;
+ JSDHashMoveEntry moveEntry;
+
+ /* Look, but don't touch, until we succeed in getting new entry store. */
+ oldLog2 = JS_DHASH_BITS - table->hashShift;
+ newLog2 = oldLog2 + deltaLog2;
+ oldCapacity = JS_BIT(oldLog2);
+ newCapacity = JS_BIT(newLog2);
+ if (newCapacity >= JS_DHASH_SIZE_LIMIT)
+ return JS_FALSE;
+ entrySize = table->entrySize;
+ nbytes = newCapacity * entrySize;
+
+ newEntryStore = table->ops->allocTable(table, nbytes);
+ if (!newEntryStore)
+ return JS_FALSE;
+
+ /* We can't fail from here on, so update table parameters. */
+ table->hashShift = JS_DHASH_BITS - newLog2;
+ table->removedCount = 0;
+ table->generation++;
+
+ /* Assign the new entry store to table. */
+ memset(newEntryStore, 0, nbytes);
+ oldEntryAddr = oldEntryStore = table->entryStore;
+ table->entryStore = newEntryStore;
+ getKey = table->ops->getKey;
+ moveEntry = table->ops->moveEntry;
+
+ /* Copy only live entries, leaving removed ones behind. */
+ for (i = 0; i < oldCapacity; i++) {
+ oldEntry = (JSDHashEntryHdr *)oldEntryAddr;
+ if (ENTRY_IS_LIVE(oldEntry)) {
+ oldEntry->keyHash &= ~COLLISION_FLAG;
+ newEntry = SearchTable(table, getKey(table, oldEntry),
+ oldEntry->keyHash, JS_DHASH_ADD);
+ JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(newEntry));
+ moveEntry(table, oldEntry, newEntry);
+ newEntry->keyHash = oldEntry->keyHash;
+ }
+ oldEntryAddr += entrySize;
+ }
+
+ table->ops->freeTable(table, oldEntryStore);
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSDHashEntryHdr *)
+JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
+{
+ JSDHashNumber keyHash;
+ JSDHashEntryHdr *entry;
+ uint32 size;
+ int deltaLog2;
+
+ keyHash = table->ops->hashKey(table, key);
+ keyHash *= JS_DHASH_GOLDEN_RATIO;
+
+ /* Avoid 0 and 1 hash codes, they indicate free and removed entries. */
+ ENSURE_LIVE_KEYHASH(keyHash);
+ keyHash &= ~COLLISION_FLAG;
+
+ switch (op) {
+ case JS_DHASH_LOOKUP:
+ METER(table->stats.lookups++);
+ entry = SearchTable(table, key, keyHash, op);
+ break;
+
+ case JS_DHASH_ADD:
+ /*
+ * If alpha is >= .75, grow or compress the table. If key is already
+ * in the table, we may grow once more than necessary, but only if we
+ * are on the edge of being overloaded.
+ */
+ size = JS_DHASH_TABLE_SIZE(table);
+ if (table->entryCount + table->removedCount >= MAX_LOAD(table, size)) {
+ /* Compress if a quarter or more of all entries are removed. */
+ if (table->removedCount >= size >> 2) {
+ METER(table->stats.compresses++);
+ deltaLog2 = 0;
+ } else {
+ METER(table->stats.grows++);
+ deltaLog2 = 1;
+ }
+
+ /*
+ * Grow or compress table, returning null if ChangeTable fails and
+ * falling through might claim the last free entry.
+ */
+ if (!ChangeTable(table, deltaLog2) &&
+ table->entryCount + table->removedCount == size - 1) {
+ METER(table->stats.addFailures++);
+ return NULL;
+ }
+ }
+
+ /*
+ * Look for entry after possibly growing, so we don't have to add it,
+ * then skip it while growing the table and re-add it after.
+ */
+ entry = SearchTable(table, key, keyHash, op);
+ if (!ENTRY_IS_LIVE(entry)) {
+ /* Initialize the entry, indicating that it's no longer free. */
+ METER(table->stats.addMisses++);
+ if (ENTRY_IS_REMOVED(entry)) {
+ METER(table->stats.addOverRemoved++);
+ table->removedCount--;
+ keyHash |= COLLISION_FLAG;
+ }
+ if (table->ops->initEntry &&
+ !table->ops->initEntry(table, entry, key)) {
+ /* We haven't claimed entry yet; fail with null return. */
+ memset(entry + 1, 0, table->entrySize - sizeof *entry);
+ return NULL;
+ }
+ entry->keyHash = keyHash;
+ table->entryCount++;
+ }
+ METER(else table->stats.addHits++);
+ break;
+
+ case JS_DHASH_REMOVE:
+ entry = SearchTable(table, key, keyHash, op);
+ if (ENTRY_IS_LIVE(entry)) {
+ /* Clear this entry and mark it as "removed". */
+ METER(table->stats.removeHits++);
+ JS_DHashTableRawRemove(table, entry);
+
+ /* Shrink if alpha is <= .25 and table isn't too small already. */
+ size = JS_DHASH_TABLE_SIZE(table);
+ if (size > JS_DHASH_MIN_SIZE &&
+ table->entryCount <= MIN_LOAD(table, size)) {
+ METER(table->stats.shrinks++);
+ (void) ChangeTable(table, -1);
+ }
+ }
+ METER(else table->stats.removeMisses++);
+ entry = NULL;
+ break;
+
+ default:
+ JS_ASSERT(0);
+ entry = NULL;
+ }
+
+ return entry;
+}
+
+JS_PUBLIC_API(void)
+JS_DHashTableRawRemove(JSDHashTable *table, JSDHashEntryHdr *entry)
+{
+ JSDHashNumber keyHash; /* load first in case clearEntry goofs it */
+
+ JS_ASSERT(JS_DHASH_ENTRY_IS_LIVE(entry));
+ keyHash = entry->keyHash;
+ table->ops->clearEntry(table, entry);
+ if (keyHash & COLLISION_FLAG) {
+ MARK_ENTRY_REMOVED(entry);
+ table->removedCount++;
+ } else {
+ METER(table->stats.removeFrees++);
+ MARK_ENTRY_FREE(entry);
+ }
+ table->entryCount--;
+}
+
+JS_PUBLIC_API(uint32)
+JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg)
+{
+ char *entryAddr, *entryLimit;
+ uint32 i, capacity, entrySize;
+ JSBool didRemove;
+ JSDHashEntryHdr *entry;
+ JSDHashOperator op;
+
+ entryAddr = table->entryStore;
+ entrySize = table->entrySize;
+ capacity = JS_DHASH_TABLE_SIZE(table);
+ entryLimit = entryAddr + capacity * entrySize;
+ i = 0;
+ didRemove = JS_FALSE;
+ while (entryAddr < entryLimit) {
+ entry = (JSDHashEntryHdr *)entryAddr;
+ if (ENTRY_IS_LIVE(entry)) {
+ op = etor(table, entry, i++, arg);
+ if (op & JS_DHASH_REMOVE) {
+ METER(table->stats.removeEnums++);
+ JS_DHashTableRawRemove(table, entry);
+ didRemove = JS_TRUE;
+ }
+ if (op & JS_DHASH_STOP)
+ break;
+ }
+ entryAddr += entrySize;
+ }
+
+ /*
+ * Shrink or compress if a quarter or more of all entries are removed, or
+ * if the table is underloaded according to the configured minimum alpha,
+ * and is not minimal-size already. Do this only if we removed above, so
+ * non-removing enumerations can count on stable table->entryStore until
+ * the next non-lookup-Operate or removing-Enumerate.
+ */
+ if (didRemove &&
+ (table->removedCount >= capacity >> 2 ||
+ (capacity > JS_DHASH_MIN_SIZE &&
+ table->entryCount <= MIN_LOAD(table, capacity)))) {
+ METER(table->stats.enumShrinks++);
+ capacity = table->entryCount;
+ capacity += capacity >> 1;
+ if (capacity < JS_DHASH_MIN_SIZE)
+ capacity = JS_DHASH_MIN_SIZE;
+ (void) ChangeTable(table,
+ JS_CeilingLog2(capacity)
+ - (JS_DHASH_BITS - table->hashShift));
+ }
+ return i;
+}
+
+#ifdef JS_DHASHMETER
+#include <math.h>
+
+JS_PUBLIC_API(void)
+JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp)
+{
+ char *entryAddr;
+ uint32 entrySize, entryCount;
+ int hashShift, sizeLog2;
+ uint32 i, tableSize, sizeMask, chainLen, maxChainLen, chainCount;
+ JSDHashNumber hash1, hash2, saveHash1, maxChainHash1, maxChainHash2;
+ double sqsum, mean, variance, sigma;
+ JSDHashEntryHdr *entry, *probe;
+
+ entryAddr = table->entryStore;
+ entrySize = table->entrySize;
+ hashShift = table->hashShift;
+ sizeLog2 = JS_DHASH_BITS - hashShift;
+ tableSize = JS_DHASH_TABLE_SIZE(table);
+ sizeMask = JS_BITMASK(sizeLog2);
+ chainCount = maxChainLen = 0;
+ hash2 = 0;
+ sqsum = 0;
+
+ for (i = 0; i < tableSize; i++) {
+ entry = (JSDHashEntryHdr *)entryAddr;
+ entryAddr += entrySize;
+ if (!ENTRY_IS_LIVE(entry))
+ continue;
+ hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift);
+ saveHash1 = hash1;
+ probe = ADDRESS_ENTRY(table, hash1);
+ chainLen = 1;
+ if (probe == entry) {
+ /* Start of a (possibly unit-length) chain. */
+ chainCount++;
+ } else {
+ hash2 = HASH2(entry->keyHash & ~COLLISION_FLAG, sizeLog2,
+ hashShift);
+ do {
+ chainLen++;
+ hash1 -= hash2;
+ hash1 &= sizeMask;
+ probe = ADDRESS_ENTRY(table, hash1);
+ } while (probe != entry);
+ }
+ sqsum += chainLen * chainLen;
+ if (chainLen > maxChainLen) {
+ maxChainLen = chainLen;
+ maxChainHash1 = saveHash1;
+ maxChainHash2 = hash2;
+ }
+ }
+
+ entryCount = table->entryCount;
+ if (entryCount && chainCount) {
+ mean = (double)entryCount / chainCount;
+ variance = chainCount * sqsum - entryCount * entryCount;
+ if (variance < 0 || chainCount == 1)
+ variance = 0;
+ else
+ variance /= chainCount * (chainCount - 1);
+ sigma = sqrt(variance);
+ } else {
+ mean = sigma = 0;
+ }
+
+ fprintf(fp, "Double hashing statistics:\n");
+ fprintf(fp, " table size (in entries): %u\n", tableSize);
+ fprintf(fp, " number of entries: %u\n", table->entryCount);
+ fprintf(fp, " number of removed entries: %u\n", table->removedCount);
+ fprintf(fp, " number of searches: %u\n", table->stats.searches);
+ fprintf(fp, " number of hits: %u\n", table->stats.hits);
+ fprintf(fp, " number of misses: %u\n", table->stats.misses);
+ fprintf(fp, " mean steps per search: %g\n", table->stats.searches ?
+ (double)table->stats.steps
+ / table->stats.searches :
+ 0.);
+ fprintf(fp, " mean hash chain length: %g\n", mean);
+ fprintf(fp, " standard deviation: %g\n", sigma);
+ fprintf(fp, " maximum hash chain length: %u\n", maxChainLen);
+ fprintf(fp, " number of lookups: %u\n", table->stats.lookups);
+ fprintf(fp, " adds that made a new entry: %u\n", table->stats.addMisses);
+ fprintf(fp, "adds that recycled removeds: %u\n", table->stats.addOverRemoved);
+ fprintf(fp, " adds that found an entry: %u\n", table->stats.addHits);
+ fprintf(fp, " add failures: %u\n", table->stats.addFailures);
+ fprintf(fp, " useful removes: %u\n", table->stats.removeHits);
+ fprintf(fp, " useless removes: %u\n", table->stats.removeMisses);
+ fprintf(fp, "removes that freed an entry: %u\n", table->stats.removeFrees);
+ fprintf(fp, " removes while enumerating: %u\n", table->stats.removeEnums);
+ fprintf(fp, " number of grows: %u\n", table->stats.grows);
+ fprintf(fp, " number of shrinks: %u\n", table->stats.shrinks);
+ fprintf(fp, " number of compresses: %u\n", table->stats.compresses);
+ fprintf(fp, "number of enumerate shrinks: %u\n", table->stats.enumShrinks);
+
+ if (dump && maxChainLen && hash2) {
+ fputs("Maximum hash chain:\n", fp);
+ hash1 = maxChainHash1;
+ hash2 = maxChainHash2;
+ entry = ADDRESS_ENTRY(table, hash1);
+ i = 0;
+ do {
+ if (dump(table, entry, i++, fp) != JS_DHASH_NEXT)
+ break;
+ hash1 -= hash2;
+ hash1 &= sizeMask;
+ entry = ADDRESS_ENTRY(table, hash1);
+ } while (JS_DHASH_ENTRY_IS_BUSY(entry));
+ }
+}
+#endif /* JS_DHASHMETER */
diff --git a/src/dom/js/jsdhash.h b/src/dom/js/jsdhash.h
new file mode 100644
index 000000000..39982ce05
--- /dev/null
+++ b/src/dom/js/jsdhash.h
@@ -0,0 +1,573 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla JavaScript code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brendan Eich <brendan@mozilla.org> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsdhash_h___
+#define jsdhash_h___
+/*
+ * Double hashing, a la Knuth 6.
+ */
+#include "jstypes.h"
+
+JS_BEGIN_EXTERN_C
+
+#ifdef DEBUG_XXXbrendan
+#define JS_DHASHMETER 1
+#endif
+
+/* Table size limit, do not equal or exceed (see min&maxAlphaFrac, below). */
+#undef JS_DHASH_SIZE_LIMIT
+#define JS_DHASH_SIZE_LIMIT JS_BIT(24)
+
+/* Minimum table size, or gross entry count (net is at most .75 loaded). */
+#ifndef JS_DHASH_MIN_SIZE
+#define JS_DHASH_MIN_SIZE 16
+#elif (JS_DHASH_MIN_SIZE & (JS_DHASH_MIN_SIZE - 1)) != 0
+#error "JS_DHASH_MIN_SIZE must be a power of two!"
+#endif
+
+/*
+ * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio,
+ * expressed as a fixed-point 32-bit fraction.
+ */
+#define JS_DHASH_BITS 32
+#define JS_DHASH_GOLDEN_RATIO 0x9E3779B9U
+
+/* Primitive and forward-struct typedefs. */
+typedef uint32 JSDHashNumber;
+typedef struct JSDHashEntryHdr JSDHashEntryHdr;
+typedef struct JSDHashEntryStub JSDHashEntryStub;
+typedef struct JSDHashTable JSDHashTable;
+typedef struct JSDHashTableOps JSDHashTableOps;
+
+/*
+ * Table entry header structure.
+ *
+ * In order to allow in-line allocation of key and value, we do not declare
+ * either here. Instead, the API uses const void *key as a formal parameter,
+ * and asks each entry for its key when necessary via a getKey callback, used
+ * when growing or shrinking the table. Other callback types are defined
+ * below and grouped into the JSDHashTableOps structure, for single static
+ * initialization per hash table sub-type.
+ *
+ * Each hash table sub-type should nest the JSDHashEntryHdr structure at the
+ * front of its particular entry type. The keyHash member contains the result
+ * of multiplying the hash code returned from the hashKey callback (see below)
+ * by JS_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0
+ * and 1 values. The stored keyHash value is table size invariant, and it is
+ * maintained automatically by JS_DHashTableOperate -- users should never set
+ * it, and its only uses should be via the entry macros below.
+ *
+ * The JS_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor
+ * removed. An entry may be either busy or free; if busy, it may be live or
+ * removed. Consumers of this API should not access members of entries that
+ * are not live.
+ *
+ * However, use JS_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries
+ * returned by JS_DHashTableOperate, as JS_DHashTableOperate never returns a
+ * non-live, busy (i.e., removed) entry pointer to its caller. See below for
+ * more details on JS_DHashTableOperate's calling rules.
+ */
+struct JSDHashEntryHdr {
+ JSDHashNumber keyHash; /* every entry must begin like this */
+};
+
+#define JS_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0)
+#define JS_DHASH_ENTRY_IS_BUSY(entry) (!JS_DHASH_ENTRY_IS_FREE(entry))
+#define JS_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2)
+
+/*
+ * A JSDHashTable is currently 8 words (without the JS_DHASHMETER overhead)
+ * on most architectures, and may be allocated on the stack or within another
+ * structure or class (see below for the Init and Finish functions to use).
+ *
+ * To decide whether to use double hashing vs. chaining, we need to develop a
+ * trade-off relation, as follows:
+ *
+ * Let alpha be the load factor, esize the entry size in words, count the
+ * entry count, and pow2 the power-of-two table size in entries.
+ *
+ * (JSDHashTable overhead) > (JSHashTable overhead)
+ * (unused table entry space) > (malloc and .next overhead per entry) +
+ * (buckets overhead)
+ * (1 - alpha) * esize * pow2 > 2 * count + pow2
+ *
+ * Notice that alpha is by definition (count / pow2):
+ *
+ * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2
+ * (1 - alpha) * esize > 2 * alpha + 1
+ *
+ * esize > (1 + 2 * alpha) / (1 - alpha)
+ *
+ * This assumes both tables must keep keyHash, key, and value for each entry,
+ * where key and value point to separately allocated strings or structures.
+ * If key and value can be combined into one pointer, then the trade-off is:
+ *
+ * esize > (1 + 3 * alpha) / (1 - alpha)
+ *
+ * If the entry value can be a subtype of JSDHashEntryHdr, rather than a type
+ * that must be allocated separately and referenced by an entry.value pointer
+ * member, and provided key's allocation can be fused with its entry's, then
+ * k (the words wasted per entry with chaining) is 4.
+ *
+ * To see these curves, feed gnuplot input like so:
+ *
+ * gnuplot> f(x,k) = (1 + k * x) / (1 - x)
+ * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4)
+ *
+ * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4
+ * words for chaining to be more space-efficient than double hashing.
+ *
+ * Solving for alpha helps us decide when to shrink an underloaded table:
+ *
+ * esize > (1 + k * alpha) / (1 - alpha)
+ * esize - alpha * esize > 1 + k * alpha
+ * esize - 1 > (k + esize) * alpha
+ * (esize - 1) / (k + esize) > alpha
+ *
+ * alpha < (esize - 1) / (esize + k)
+ *
+ * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k),
+ * assuming esize is not too large (in which case, chaining should probably be
+ * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3
+ * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5
+ * would still obtain. See the JS_DHASH_MIN_ALPHA macro further below.
+ *
+ * The current implementation uses a configurable lower bound on alpha, which
+ * defaults to .25, when deciding to shrink the table (while still respecting
+ * JS_DHASH_MIN_SIZE).
+ *
+ * Note a qualitative difference between chaining and double hashing: under
+ * chaining, entry addresses are stable across table shrinks and grows. With
+ * double hashing, you can't safely hold an entry pointer and use it after an
+ * ADD or REMOVE operation, unless you sample table->generation before adding
+ * or removing, and compare the sample after, dereferencing the entry pointer
+ * only if table->generation has not changed.
+ *
+ * The moral of this story: there is no one-size-fits-all hash table scheme,
+ * but for small table entry size, and assuming entry address stability is not
+ * required, double hashing wins.
+ */
+struct JSDHashTable {
+ const JSDHashTableOps *ops; /* virtual operations, see below */
+ void *data; /* ops- and instance-specific data */
+ int16 hashShift; /* multiplicative hash shift */
+ uint8 maxAlphaFrac; /* 8-bit fixed point max alpha */
+ uint8 minAlphaFrac; /* 8-bit fixed point min alpha */
+ uint32 entrySize; /* number of bytes in an entry */
+ uint32 entryCount; /* number of entries in table */
+ uint32 removedCount; /* removed entry sentinels in table */
+ uint32 generation; /* entry storage generation number */
+ char *entryStore; /* entry storage */
+#ifdef JS_DHASHMETER
+ struct JSDHashStats {
+ uint32 searches; /* total number of table searches */
+ uint32 steps; /* hash chain links traversed */
+ uint32 hits; /* searches that found key */
+ uint32 misses; /* searches that didn't find key */
+ uint32 lookups; /* number of JS_DHASH_LOOKUPs */
+ uint32 addMisses; /* adds that miss, and do work */
+ uint32 addOverRemoved; /* adds that recycled a removed entry */
+ uint32 addHits; /* adds that hit an existing entry */
+ uint32 addFailures; /* out-of-memory during add growth */
+ uint32 removeHits; /* removes that hit, and do work */
+ uint32 removeMisses; /* useless removes that miss */
+ uint32 removeFrees; /* removes that freed entry directly */
+ uint32 removeEnums; /* removes done by Enumerate */
+ uint32 grows; /* table expansions */
+ uint32 shrinks; /* table contractions */
+ uint32 compresses; /* table compressions */
+ uint32 enumShrinks; /* contractions after Enumerate */
+ } stats;
+#endif
+};
+
+/*
+ * Size in entries (gross, not net of free and removed sentinels) for table.
+ * We store hashShift rather than sizeLog2 to optimize the collision-free case
+ * in SearchTable.
+ */
+#define JS_DHASH_TABLE_SIZE(table) JS_BIT(JS_DHASH_BITS - (table)->hashShift)
+
+/*
+ * Table space at entryStore is allocated and freed using these callbacks.
+ * The allocator should return null on error only (not if called with nbytes
+ * equal to 0; but note that jsdhash.c code will never call with 0 nbytes).
+ */
+typedef void *
+(* JS_DLL_CALLBACK JSDHashAllocTable)(JSDHashTable *table, uint32 nbytes);
+
+typedef void
+(* JS_DLL_CALLBACK JSDHashFreeTable) (JSDHashTable *table, void *ptr);
+
+/*
+ * When a table grows or shrinks, each entry is queried for its key using this
+ * callback. NB: in that event, entry is not in table any longer; it's in the
+ * old entryStore vector, which is due to be freed once all entries have been
+ * moved via moveEntry callbacks.
+ */
+typedef const void *
+(* JS_DLL_CALLBACK JSDHashGetKey) (JSDHashTable *table,
+ JSDHashEntryHdr *entry);
+
+/*
+ * Compute the hash code for a given key to be looked up, added, or removed
+ * from table. A hash code may have any JSDHashNumber value.
+ */
+typedef JSDHashNumber
+(* JS_DLL_CALLBACK JSDHashHashKey) (JSDHashTable *table, const void *key);
+
+/*
+ * Compare the key identifying entry in table with the provided key parameter.
+ * Return JS_TRUE if keys match, JS_FALSE otherwise.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSDHashMatchEntry)(JSDHashTable *table,
+ const JSDHashEntryHdr *entry,
+ const void *key);
+
+/*
+ * Copy the data starting at from to the new entry storage at to. Do not add
+ * reference counts for any strong references in the entry, however, as this
+ * is a "move" operation: the old entry storage at from will be freed without
+ * any reference-decrementing callback shortly.
+ */
+typedef void
+(* JS_DLL_CALLBACK JSDHashMoveEntry)(JSDHashTable *table,
+ const JSDHashEntryHdr *from,
+ JSDHashEntryHdr *to);
+
+/*
+ * Clear the entry and drop any strong references it holds. This callback is
+ * invoked during a JS_DHASH_REMOVE operation (see below for operation codes),
+ * but only if the given key is found in the table.
+ */
+typedef void
+(* JS_DLL_CALLBACK JSDHashClearEntry)(JSDHashTable *table,
+ JSDHashEntryHdr *entry);
+
+/*
+ * Called when a table (whether allocated dynamically by itself, or nested in
+ * a larger structure, or allocated on the stack) is finished. This callback
+ * allows table->ops-specific code to finalize table->data.
+ */
+typedef void
+(* JS_DLL_CALLBACK JSDHashFinalize) (JSDHashTable *table);
+
+/*
+ * Initialize a new entry, apart from keyHash. This function is called when
+ * JS_DHashTableOperate's JS_DHASH_ADD case finds no existing entry for the
+ * given key, and must add a new one. At that point, entry->keyHash is not
+ * set yet, to avoid claiming the last free entry in a severely overloaded
+ * table.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSDHashInitEntry)(JSDHashTable *table,
+ JSDHashEntryHdr *entry,
+ const void *key);
+
+/*
+ * Finally, the "vtable" structure for JSDHashTable. The first eight hooks
+ * must be provided by implementations; they're called unconditionally by the
+ * generic jsdhash.c code. Hooks after these may be null.
+ *
+ * Summary of allocation-related hook usage with C++ placement new emphasis:
+ * allocTable Allocate raw bytes with malloc, no ctors run.
+ * freeTable Free raw bytes with free, no dtors run.
+ * initEntry Call placement new using default key-based ctor.
+ * Return JS_TRUE on success, JS_FALSE on error.
+ * moveEntry Call placement new using copy ctor, run dtor on old
+ * entry storage.
+ * clearEntry Run dtor on entry.
+ * finalize Stub unless table->data was initialized and needs to
+ * be finalized.
+ *
+ * Note the reason why initEntry is optional: the default hooks (stubs) clear
+ * entry storage: On successful JS_DHashTableOperate(tbl, key, JS_DHASH_ADD),
+ * the returned entry pointer addresses an entry struct whose keyHash member
+ * has been set non-zero, but all other entry members are still clear (null).
+ * JS_DHASH_ADD callers can test such members to see whether the entry was
+ * newly created by the JS_DHASH_ADD call that just succeeded. If placement
+ * new or similar initialization is required, define an initEntry hook. Of
+ * course, the clearEntry hook must zero or null appropriately.
+ *
+ * XXX assumes 0 is null for pointer types.
+ */
+struct JSDHashTableOps {
+ /* Mandatory hooks. All implementations must provide these. */
+ JSDHashAllocTable allocTable;
+ JSDHashFreeTable freeTable;
+ JSDHashGetKey getKey;
+ JSDHashHashKey hashKey;
+ JSDHashMatchEntry matchEntry;
+ JSDHashMoveEntry moveEntry;
+ JSDHashClearEntry clearEntry;
+ JSDHashFinalize finalize;
+
+ /* Optional hooks start here. If null, these are not called. */
+ JSDHashInitEntry initEntry;
+};
+
+/*
+ * Default implementations for the above ops.
+ */
+extern JS_PUBLIC_API(void *)
+JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes);
+
+extern JS_PUBLIC_API(void)
+JS_DHashFreeTable(JSDHashTable *table, void *ptr);
+
+extern JS_PUBLIC_API(JSDHashNumber)
+JS_DHashStringKey(JSDHashTable *table, const void *key);
+
+/* A minimal entry contains a keyHash header and a void key pointer. */
+struct JSDHashEntryStub {
+ JSDHashEntryHdr hdr;
+ const void *key;
+};
+
+extern JS_PUBLIC_API(const void *)
+JS_DHashGetKeyStub(JSDHashTable *table, JSDHashEntryHdr *entry);
+
+extern JS_PUBLIC_API(JSDHashNumber)
+JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DHashMatchEntryStub(JSDHashTable *table,
+ const JSDHashEntryHdr *entry,
+ const void *key);
+
+extern JS_PUBLIC_API(JSBool)
+JS_DHashMatchStringKey(JSDHashTable *table,
+ const JSDHashEntryHdr *entry,
+ const void *key);
+
+extern JS_PUBLIC_API(void)
+JS_DHashMoveEntryStub(JSDHashTable *table,
+ const JSDHashEntryHdr *from,
+ JSDHashEntryHdr *to);
+
+extern JS_PUBLIC_API(void)
+JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry);
+
+extern JS_PUBLIC_API(void)
+JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry);
+
+extern JS_PUBLIC_API(void)
+JS_DHashFinalizeStub(JSDHashTable *table);
+
+/*
+ * If you use JSDHashEntryStub or a subclass of it as your entry struct, and
+ * if your entries move via memcpy and clear via memset(0), you can use these
+ * stub operations.
+ */
+extern JS_PUBLIC_API(const JSDHashTableOps *)
+JS_DHashGetStubOps(void);
+
+/*
+ * Dynamically allocate a new JSDHashTable using malloc, initialize it using
+ * JS_DHashTableInit, and return its address. Return null on malloc failure.
+ * Note that the entry storage at table->entryStore will be allocated using
+ * the ops->allocTable callback.
+ */
+extern JS_PUBLIC_API(JSDHashTable *)
+JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize,
+ uint32 capacity);
+
+/*
+ * Finalize table's data, free its entry storage (via table->ops->freeTable),
+ * and return the memory starting at table to the malloc heap.
+ */
+extern JS_PUBLIC_API(void)
+JS_DHashTableDestroy(JSDHashTable *table);
+
+/*
+ * Initialize table with ops, data, entrySize, and capacity. Capacity is a
+ * guess for the smallest table size at which the table will usually be less
+ * than 75% loaded (the table will grow or shrink as needed; capacity serves
+ * only to avoid inevitable early growth from JS_DHASH_MIN_SIZE).
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data,
+ uint32 entrySize, uint32 capacity);
+
+/*
+ * Set maximum and minimum alpha for table. The defaults are 0.75 and .25.
+ * maxAlpha must be in [0.5, 0.9375] for the default JS_DHASH_MIN_SIZE; or if
+ * MinSize=JS_DHASH_MIN_SIZE <= 256, in [0.5, (float)(MinSize-1)/MinSize]; or
+ * else in [0.5, 255.0/256]. minAlpha must be in [0, maxAlpha / 2), so that
+ * we don't shrink on the very next remove after growing a table upon adding
+ * an entry that brings entryCount past maxAlpha * tableSize.
+ */
+JS_PUBLIC_API(void)
+JS_DHashTableSetAlphaBounds(JSDHashTable *table,
+ float maxAlpha,
+ float minAlpha);
+
+/*
+ * Call this macro with k, the number of pointer-sized words wasted per entry
+ * under chaining, to compute the minimum alpha at which double hashing still
+ * beats chaining.
+ */
+#define JS_DHASH_MIN_ALPHA(table, k) \
+ ((float)((table)->entrySize / sizeof(void *) - 1) \
+ / ((table)->entrySize / sizeof(void *) + (k)))
+
+/*
+ * Finalize table's data, free its entry storage using table->ops->freeTable,
+ * and leave its members unchanged from their last live values (which leaves
+ * pointers dangling). If you want to burn cycles clearing table, it's up to
+ * your code to call memset.
+ */
+extern JS_PUBLIC_API(void)
+JS_DHashTableFinish(JSDHashTable *table);
+
+/*
+ * To consolidate keyHash computation and table grow/shrink code, we use a
+ * single entry point for lookup, add, and remove operations. The operation
+ * codes are declared here, along with codes returned by JSDHashEnumerator
+ * functions, which control JS_DHashTableEnumerate's behavior.
+ */
+typedef enum JSDHashOperator {
+ JS_DHASH_LOOKUP = 0, /* lookup entry */
+ JS_DHASH_ADD = 1, /* add entry */
+ JS_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */
+ JS_DHASH_NEXT = 0, /* enumerator says continue */
+ JS_DHASH_STOP = 1 /* enumerator says stop */
+} JSDHashOperator;
+
+/*
+ * To lookup a key in table, call:
+ *
+ * entry = JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP);
+ *
+ * If JS_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies
+ * entry. If JS_DHASH_ENTRY_IS_FREE(entry) is true, key was not found.
+ *
+ * To add an entry identified by key to table, call:
+ *
+ * entry = JS_DHashTableOperate(table, key, JS_DHASH_ADD);
+ *
+ * If entry is null upon return, then either the table is severely overloaded,
+ * and memory can't be allocated for entry storage via table->ops->allocTable;
+ * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may
+ * have returned false.
+ *
+ * Otherwise, entry->keyHash has been set so that JS_DHASH_ENTRY_IS_BUSY(entry)
+ * is true, and it is up to the caller to initialize the key and value parts
+ * of the entry sub-type, if they have not been set already (i.e. if entry was
+ * not already in the table, and if the optional initEntry hook was not used).
+ *
+ * To remove an entry identified by key from table, call:
+ *
+ * (void) JS_DHashTableOperate(table, key, JS_DHASH_REMOVE);
+ *
+ * If key's entry is found, it is cleared (via table->ops->clearEntry) and
+ * the entry is marked so that JS_DHASH_ENTRY_IS_FREE(entry). This operation
+ * returns null unconditionally; you should ignore its return value.
+ */
+extern JS_PUBLIC_API(JSDHashEntryHdr *)
+JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op);
+
+/*
+ * Remove an entry already accessed via LOOKUP or ADD.
+ *
+ * NB: this is a "raw" or low-level routine, intended to be used only where
+ * the inefficiency of a full JS_DHashTableOperate (which rehashes in order
+ * to find the entry given its key) is not tolerable. This function does not
+ * shrink the table if it is underloaded. It does not update stats #ifdef
+ * JS_DHASHMETER, either.
+ */
+extern JS_PUBLIC_API(void)
+JS_DHashTableRawRemove(JSDHashTable *table, JSDHashEntryHdr *entry);
+
+/*
+ * Enumerate entries in table using etor:
+ *
+ * count = JS_DHashTableEnumerate(table, etor, arg);
+ *
+ * JS_DHashTableEnumerate calls etor like so:
+ *
+ * op = etor(table, entry, number, arg);
+ *
+ * where number is a zero-based ordinal assigned to live entries according to
+ * their order in table->entryStore.
+ *
+ * The return value, op, is treated as a set of flags. If op is JS_DHASH_NEXT,
+ * then continue enumerating. If op contains JS_DHASH_REMOVE, then clear (via
+ * table->ops->clearEntry) and free entry. Then we check whether op contains
+ * JS_DHASH_STOP; if so, stop enumerating and return the number of live entries
+ * that were enumerated so far. Return the total number of live entries when
+ * enumeration completes normally.
+ *
+ * If etor calls JS_DHashTableOperate on table with op != JS_DHASH_LOOKUP, it
+ * must return JS_DHASH_STOP; otherwise undefined behavior results.
+ *
+ * If any enumerator returns JS_DHASH_REMOVE, table->entryStore may be shrunk
+ * or compressed after enumeration, but before JS_DHashTableEnumerate returns.
+ * Such an enumerator therefore can't safely set aside entry pointers, but an
+ * enumerator that never returns JS_DHASH_REMOVE can set pointers to entries
+ * aside, e.g., to avoid copying live entries into an array of the entry type.
+ * Copying entry pointers is cheaper, and safe so long as the caller of such a
+ * "stable" Enumerate doesn't use the set-aside pointers after any call either
+ * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might
+ * grow or shrink entryStore.
+ *
+ * If your enumerator wants to remove certain entries, but set aside pointers
+ * to other entries that it retains, it can use JS_DHashTableRawRemove on the
+ * entries to be removed, returning JS_DHASH_NEXT to skip them. Likewise, if
+ * you want to remove entries, but for some reason you do not want entryStore
+ * to be shrunk or compressed, you can call JS_DHashTableRawRemove safely on
+ * the entry being enumerated, rather than returning JS_DHASH_REMOVE.
+ */
+typedef JSDHashOperator
+(* JS_DLL_CALLBACK JSDHashEnumerator)(JSDHashTable *table, JSDHashEntryHdr *hdr,
+ uint32 number, void *arg);
+
+extern JS_PUBLIC_API(uint32)
+JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg);
+
+#ifdef JS_DHASHMETER
+#include <stdio.h>
+
+extern JS_PUBLIC_API(void)
+JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp);
+#endif
+
+JS_END_EXTERN_C
+
+#endif /* jsdhash_h___ */
diff --git a/src/dom/js/jsdtoa.c b/src/dom/js/jsdtoa.c
new file mode 100644
index 000000000..2bd163d75
--- /dev/null
+++ b/src/dom/js/jsdtoa.c
@@ -0,0 +1,3155 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Portable double to alphanumeric string and back converters.
+ */
+#include "jsstddef.h"
+#include "jslibmath.h"
+#include "jstypes.h"
+#include "jsdtoa.h"
+#include "jsprf.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jspubtd.h"
+#include "jsnum.h"
+
+#ifdef JS_THREADSAFE
+#include "prlock.h"
+#endif
+
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to
+ David M. Gay
+ Bell Laboratories, Room 2C-463
+ 600 Mountain Avenue
+ Murray Hill, NJ 07974-0636
+ U.S.A.
+ dmg@bell-labs.com
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets err to JS_DTOA_ERANGE or JS_DTOA_ENOMEM). With IEEE
+ * arithmetic, ties are broken by the IEEE round-even rule. Otherwise
+ * ties are broken by biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ * significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ * significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ * underflow (i.e., that flush to zero on underflow).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ * computation of js_dtoa.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ * that use extended-precision instructions to compute rounded
+ * products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define JS_HAVE_LONG_LONG on machines that have a "long long"
+ * integer type (of >= 64 bits). If long long is available and the name is
+ * something other than "long long", #define Llong to be the name,
+ * and if "unsigned Llong" does not work as an unsigned version of
+ * Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ * if memory is available and otherwise does something you deem
+ * appropriate. If MALLOC is undefined, malloc will be invoked
+ * directly -- and assumed always to succeed.
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ * memory allocations from a private pool of memory when possible.
+ * When used, the private pool is PRIVATE_MEM bytes long: 2000 bytes,
+ * unless #defined to be a different length. This default length
+ * suffices to get rid of MALLOC calls except for unusual cases,
+ * such as decimal-to-binary conversion of a very long string of
+ * digits.
+ * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
+ * Infinity and NaN (case insensitively). On some systems (e.g.,
+ * some HP systems), it may be necessary to #define NAN_WORD0
+ * appropriately -- to the most significant word of a quiet NaN.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ * multiple threads. In this case, you must provide (or suitably
+ * #define) two locks, acquired by ACQUIRE_DTOA_LOCK() and released
+ * by RELEASE_DTOA_LOCK(). (The second lock, accessed
+ * in pow5mult, ensures lazy evaluation of only one copy of high
+ * powers of 5; omitting this lock would introduce a small
+ * probability of wasting memory, but would otherwise be harmless.)
+ * You must also invoke freedtoa(s) to free the value s returned by
+ * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ * avoids underflows on inputs whose result does not underflow.
+ */
+#ifdef IS_LITTLE_ENDIAN
+#define IEEE_8087
+#else
+#define IEEE_MC68k
+#endif
+
+#ifndef Long
+#define Long int32
+#endif
+
+#ifndef ULong
+#define ULong uint32
+#endif
+
+#define Bug(errorMessageString) JS_ASSERT(!errorMessageString)
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef MALLOC
+extern void *MALLOC(size_t);
+#else
+#define MALLOC malloc
+#endif
+
+#define Omit_Private_Memory
+/* Private memory currently doesn't work with JS_THREADSAFE */
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2000
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#ifdef Bad_float_h
+#undef __STDC__
+
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#define FLT_ROUNDS 1
+#define DBL_MAX 1.7976931348623157e+308
+
+
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+/*
+ * MacOS 10.2 defines the macro FLT_ROUNDS to an internal function
+ * which does not exist on 10.1. We can safely #define it to 1 here
+ * to allow 10.2 builds to run on 10.1, since we can't use fesetround()
+ * (which does not exist on 10.1 either).
+ */
+#if defined(MACOS_DEPLOYMENT_TARGET) && (MACOS_DEPLOYMENT_TARGET < 100200)
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+#endif
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifndef CONST
+#define CONST const
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) != 1
+Exactly one of IEEE_8087 or IEEE_MC68k should be defined.
+#endif
+
+#define word0(x) JSDOUBLE_HI32(x)
+#define set_word0(x, y) JSDOUBLE_SET_HI32(x, y)
+#define word1(x) JSDOUBLE_LO32(x)
+#define set_word1(x, y) JSDOUBLE_SET_LO32(x, y)
+
+#define Storeinc(a,b,c) (*(a)++ = (b) << 16 | (c) & 0xffff)
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#define Infinite(x) (word0(x) == 0x7ff00000) /* sufficient test for here */
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#endif
+
+
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef JS_HAVE_LONG_LONG
+#undef ULLong
+#else /* long long available */
+#ifndef Llong
+#define Llong JSInt64
+#endif
+#ifndef ULLong
+#define ULLong JSUint64
+#endif
+#endif /* JS_HAVE_LONG_LONG */
+
+#ifdef JS_THREADSAFE
+#define MULTIPLE_THREADS
+static PRLock *freelist_lock;
+#define ACQUIRE_DTOA_LOCK() \
+ JS_BEGIN_MACRO \
+ if (!initialized) \
+ InitDtoa(); \
+ PR_Lock(freelist_lock); \
+ JS_END_MACRO
+#define RELEASE_DTOA_LOCK() PR_Unlock(freelist_lock)
+#else
+#undef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK() /*nothing*/
+#define RELEASE_DTOA_LOCK() /*nothing*/
+#endif
+
+#define Kmax 15
+
+struct Bigint {
+ struct Bigint *next; /* Free list link */
+ int32 k; /* lg2(maxwds) */
+ int32 maxwds; /* Number of words allocated for x */
+ int32 sign; /* Zero if positive, 1 if negative. Ignored by most Bigint routines! */
+ int32 wds; /* Actual number of words. If value is nonzero, the most significant word must be nonzero. */
+ ULong x[1]; /* wds words of number in little endian order */
+};
+
+#ifdef ENABLE_OOM_TESTING
+/* Out-of-memory testing. Use a good testcase (over and over) and then use
+ * these routines to cause a memory failure on every possible Balloc allocation,
+ * to make sure that all out-of-memory paths can be followed. See bug 14044.
+ */
+
+static int allocationNum; /* which allocation is next? */
+static int desiredFailure; /* which allocation should fail? */
+
+/**
+ * js_BigintTestingReset
+ *
+ * Call at the beginning of a test run to set the allocation failure position.
+ * (Set to 0 to just have the engine count allocations without failing.)
+ */
+JS_PUBLIC_API(void)
+js_BigintTestingReset(int newFailure)
+{
+ allocationNum = 0;
+ desiredFailure = newFailure;
+}
+
+/**
+ * js_BigintTestingWhere
+ *
+ * Report the current allocation position. This is really only useful when you
+ * want to learn how many allocations a test run has.
+ */
+JS_PUBLIC_API(int)
+js_BigintTestingWhere()
+{
+ return allocationNum;
+}
+
+
+/*
+ * So here's what you do: Set up a fantastic test case that exercises the
+ * elements of the code you wish. Set the failure point at 0 and run the test,
+ * then get the allocation position. This number is the number of allocations
+ * your test makes. Now loop from 1 to that number, setting the failure point
+ * at each loop count, and run the test over and over, causing failures at each
+ * step. Any memory failure *should* cause a Out-Of-Memory exception; if it
+ * doesn't, then there's still an error here.
+ */
+#endif
+
+typedef struct Bigint Bigint;
+
+static Bigint *freelist[Kmax+1];
+
+/*
+ * Allocate a Bigint with 2^k words.
+ * This is not threadsafe. The caller must use thread locks
+ */
+static Bigint *Balloc(int32 k)
+{
+ int32 x;
+ Bigint *rv;
+#ifndef Omit_Private_Memory
+ uint32 len;
+#endif
+
+#ifdef ENABLE_OOM_TESTING
+ if (++allocationNum == desiredFailure) {
+ printf("Forced Failing Allocation number %d\n", allocationNum);
+ return NULL;
+ }
+#endif
+
+ if ((rv = freelist[k]) != NULL)
+ freelist[k] = rv->next;
+ if (rv == NULL) {
+ x = 1 << k;
+#ifdef Omit_Private_Memory
+ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+ len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+ /sizeof(double);
+ if (pmem_next - private_mem + len <= PRIVATE_mem) {
+ rv = (Bigint*)pmem_next;
+ pmem_next += len;
+ }
+ else
+ rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+ if (!rv)
+ return NULL;
+ rv->k = k;
+ rv->maxwds = x;
+ }
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+static void Bfree(Bigint *v)
+{
+ if (v) {
+ v->next = freelist[v->k];
+ freelist[v->k] = v;
+ }
+}
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+ y->wds*sizeof(Long) + 2*sizeof(int32))
+
+/* Return b*m + a. Deallocate the old b. Both a and m must be between 0 and
+ * 65535 inclusive. NOTE: old b is deallocated on memory failure.
+ */
+static Bigint *multadd(Bigint *b, int32 m, int32 a)
+{
+ int32 i, wds;
+#ifdef ULLong
+ ULong *x;
+ ULLong carry, y;
+#else
+ ULong carry, *x, y;
+ ULong xi, z;
+#endif
+ Bigint *b1;
+
+#ifdef ENABLE_OOM_TESTING
+ if (++allocationNum == desiredFailure) {
+ /* Faux allocation, because I'm not getting all of the failure paths
+ * without it.
+ */
+ printf("Forced Failing Allocation number %d\n", allocationNum);
+ Bfree(b);
+ return NULL;
+ }
+#endif
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ carry = a;
+ do {
+#ifdef ULLong
+ y = *x * (ULLong)m + carry;
+ carry = y >> 32;
+ *x++ = (ULong)(y & 0xffffffffUL);
+#else
+ xi = *x;
+ y = (xi & 0xffff) * m + carry;
+ z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#endif
+ }
+ while(++i < wds);
+ if (carry) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ if (!b1) {
+ Bfree(b);
+ return NULL;
+ }
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = (ULong)carry;
+ b->wds = wds;
+ }
+ return b;
+}
+
+static Bigint *s2b(CONST char *s, int32 nd0, int32 nd, ULong y9)
+{
+ Bigint *b;
+ int32 i, k;
+ Long x, y;
+
+ x = (nd + 8) / 9;
+ for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+ b = Balloc(k);
+ if (!b)
+ return NULL;
+ b->x[0] = y9;
+ b->wds = 1;
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do {
+ b = multadd(b, 10, *s++ - '0');
+ if (!b)
+ return NULL;
+ } while(++i < nd0);
+ s++;
+ }
+ else
+ s += 10;
+ for(; i < nd; i++) {
+ b = multadd(b, 10, *s++ - '0');
+ if (!b)
+ return NULL;
+ }
+ return b;
+}
+
+
+/* Return the number (0 through 32) of most significant zero bits in x. */
+static int32 hi0bits(register ULong x)
+{
+ register int32 k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+
+
+/* Return the number (0 through 32) of least significant zero bits in y.
+ * Also shift y to the right past these 0 through 32 zeros so that y's
+ * least significant bit will be set unless y was originally zero. */
+static int32 lo0bits(ULong *y)
+{
+ register int32 k;
+ register ULong x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x & 1)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+
+/* Return a new Bigint with the given integer value, which must be nonnegative. */
+static Bigint *i2b(int32 i)
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ if (!b)
+ return NULL;
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+/* Return a newly allocated product of a and b. */
+static Bigint *mult(CONST Bigint *a, CONST Bigint *b)
+{
+ CONST Bigint *t;
+ Bigint *c;
+ int32 k, wa, wb, wc;
+ ULong y;
+ ULong *xc, *xc0, *xce;
+ CONST ULong *x, *xa, *xae, *xb, *xbe;
+#ifdef ULLong
+ ULLong carry, z;
+#else
+ ULong carry, z;
+ ULong z2;
+#endif
+
+ if (a->wds < b->wds) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ if (!c)
+ return NULL;
+ for(xc = c->x, xce = xc + wc; xc < xce; xc++)
+ *xc = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef ULLong
+ for(; xb < xbe; xc0++) {
+ if ((y = *xb++) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (ULLong)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = (ULong)(z & 0xffffffffUL);
+ }
+ while(x < xae);
+ *xc = (ULong)carry;
+ }
+ }
+#else
+ for(; xb < xbe; xb++, xc0++) {
+ if ((y = *xb & 0xffff) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ }
+ while(x < xae);
+ *xc = carry;
+ }
+ if ((y = *xb >> 16) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ }
+ while(x < xae);
+ *xc = z2;
+ }
+ }
+#endif
+ for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+ c->wds = wc;
+ return c;
+}
+
+/*
+ * 'p5s' points to a linked list of Bigints that are powers of 5.
+ * This list grows on demand, and it can only grow: it won't change
+ * in any other way. So if we read 'p5s' or the 'next' field of
+ * some Bigint on the list, and it is not NULL, we know it won't
+ * change to NULL or some other value. Only when the value of
+ * 'p5s' or 'next' is NULL do we need to acquire the lock and add
+ * a new Bigint to the list.
+ */
+
+static Bigint *p5s;
+
+#ifdef JS_THREADSAFE
+static PRLock *p5s_lock;
+#endif
+
+/* Return b * 5^k. Deallocate the old b. k must be nonnegative. */
+/* NOTE: old b is deallocated on memory failure. */
+static Bigint *pow5mult(Bigint *b, int32 k)
+{
+ Bigint *b1, *p5, *p51;
+ int32 i;
+ static CONST int32 p05[3] = { 5, 25, 125 };
+
+ if ((i = k & 3) != 0) {
+ b = multadd(b, p05[i-1], 0);
+ if (!b)
+ return NULL;
+ }
+
+ if (!(k >>= 2))
+ return b;
+ if (!(p5 = p5s)) {
+#ifdef JS_THREADSAFE
+ /*
+ * We take great care to not call i2b() and Bfree()
+ * while holding the lock.
+ */
+ Bigint *wasted_effort = NULL;
+ p5 = i2b(625);
+ if (!p5) {
+ Bfree(b);
+ return NULL;
+ }
+ /* lock and check again */
+ PR_Lock(p5s_lock);
+ if (!p5s) {
+ /* first time */
+ p5s = p5;
+ p5->next = 0;
+ } else {
+ /* some other thread just beat us */
+ wasted_effort = p5;
+ p5 = p5s;
+ }
+ PR_Unlock(p5s_lock);
+ if (wasted_effort) {
+ Bfree(wasted_effort);
+ }
+#else
+ /* first time */
+ p5 = p5s = i2b(625);
+ if (!p5) {
+ Bfree(b);
+ return NULL;
+ }
+ p5->next = 0;
+#endif
+ }
+ for(;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ if (!b1)
+ return NULL;
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+ if (!(p51 = p5->next)) {
+#ifdef JS_THREADSAFE
+ Bigint *wasted_effort = NULL;
+ p51 = mult(p5, p5);
+ if (!p51) {
+ Bfree(b);
+ return NULL;
+ }
+ PR_Lock(p5s_lock);
+ if (!p5->next) {
+ p5->next = p51;
+ p51->next = 0;
+ } else {
+ wasted_effort = p51;
+ p51 = p5->next;
+ }
+ PR_Unlock(p5s_lock);
+ if (wasted_effort) {
+ Bfree(wasted_effort);
+ }
+#else
+ p51 = mult(p5,p5);
+ if (!p51) {
+ Bfree(b);
+ return NULL;
+ }
+ p51->next = 0;
+ p5->next = p51;
+#endif
+ }
+ p5 = p51;
+ }
+ return b;
+}
+
+/* Return b * 2^k. Deallocate the old b. k must be nonnegative.
+ * NOTE: on memory failure, old b is deallocated. */
+static Bigint *lshift(Bigint *b, int32 k)
+{
+ int32 i, k1, n, n1;
+ Bigint *b1;
+ ULong *x, *x1, *xe, z;
+
+ n = k >> 5;
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for(i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ if (!b1)
+ goto done;
+ x1 = b1->x;
+ for(i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ }
+ while(x < xe);
+ if ((*x1 = z) != 0)
+ ++n1;
+ }
+ else do
+ *x1++ = *x++;
+ while(x < xe);
+ b1->wds = n1 - 1;
+done:
+ Bfree(b);
+ return b1;
+}
+
+/* Return -1, 0, or 1 depending on whether a<b, a==b, or a>b, respectively. */
+static int32 cmp(Bigint *a, Bigint *b)
+{
+ ULong *xa, *xa0, *xb, *xb0;
+ int32 i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i-1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j-1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for(;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+static Bigint *diff(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int32 i, wa, wb;
+ ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+ ULLong borrow, y;
+#else
+ ULong borrow, y;
+ ULong z;
+#endif
+
+ i = cmp(a,b);
+ if (!i) {
+ c = Balloc(0);
+ if (!c)
+ return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ }
+ else
+ i = 0;
+ c = Balloc(a->k);
+ if (!c)
+ return NULL;
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef ULLong
+ do {
+ y = (ULLong)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & 1UL;
+ *xc++ = (ULong)(y & 0xffffffffUL);
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = *xa++ - borrow;
+ borrow = y >> 32 & 1UL;
+ *xc++ = (ULong)(y & 0xffffffffUL);
+ }
+#else
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#endif
+ while(!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+/* Return the absolute difference between x and the adjacent greater-magnitude double number (ignoring exponent overflows). */
+static double ulp(double x)
+{
+ register Long L;
+ double a;
+
+ L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+ set_word0(a, L);
+ set_word1(a, 0);
+#ifndef Sudden_Underflow
+ }
+ else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ set_word0(a, 0x80000 >> L);
+ set_word1(a, 0);
+ }
+ else {
+ set_word0(a, 0);
+ L -= Exp_shift;
+ set_word1(a, L >= 31 ? 1 : 1 << (31 - L));
+ }
+ }
+#endif
+ return a;
+}
+
+
+static double b2d(Bigint *a, int32 *e)
+{
+ ULong *xa, *xa0, w, y, z;
+ int32 k;
+ double d;
+#define d0 word0(d)
+#define d1 word1(d)
+#define set_d0(x) set_word0(d, x)
+#define set_d1(x) set_word1(d, x)
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y) Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+ if (k < Ebits) {
+ set_d0(Exp_1 | y >> (Ebits - k));
+ w = xa > xa0 ? *--xa : 0;
+ set_d1(y << (32-Ebits + k) | w >> (Ebits - k));
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ set_d0(Exp_1 | y << k | z >> (32 - k));
+ y = xa > xa0 ? *--xa : 0;
+ set_d1(z << k | y >> (32 - k));
+ }
+ else {
+ set_d0(Exp_1 | y);
+ set_d1(z);
+ }
+ ret_d:
+#undef d0
+#undef d1
+#undef set_d0
+#undef set_d1
+ return d;
+}
+
+
+/* Convert d into the form b*2^e, where b is an odd integer. b is the returned
+ * Bigint and e is the returned binary exponent. Return the number of significant
+ * bits in b in bits. d must be finite and nonzero. */
+static Bigint *d2b(double d, int32 *e, int32 *bits)
+{
+ Bigint *b;
+ int32 de, i, k;
+ ULong *x, y, z;
+#define d0 word0(d)
+#define d1 word1(d)
+#define set_d0(x) set_word0(d, x)
+#define set_d1(x) set_word1(d, x)
+
+ b = Balloc(1);
+ if (!b)
+ return NULL;
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ set_d0(d0 & 0x7fffffff); /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int32)(d0 >> Exp_shift);
+ z |= Exp_msk11;
+#else
+ if ((de = (int32)(d0 >> Exp_shift)) != 0)
+ z |= Exp_msk1;
+#endif
+ if ((y = d1) != 0) {
+ if ((k = lo0bits(&y)) != 0) {
+ x[0] = y | z << (32 - k);
+ z >>= k;
+ }
+ else
+ x[0] = y;
+ i = b->wds = (x[1] = z) ? 2 : 1;
+ }
+ else {
+ JS_ASSERT(z);
+ k = lo0bits(&z);
+ x[0] = z;
+ i = b->wds = 1;
+ k += 32;
+ }
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+ *e = de - Bias - (P-1) + k;
+ *bits = P - k;
+#ifndef Sudden_Underflow
+ }
+ else {
+ *e = de - Bias - (P-1) + 1 + k;
+ *bits = 32*i - hi0bits(x[i-1]);
+ }
+#endif
+ return b;
+}
+#undef d0
+#undef d1
+#undef set_d0
+#undef set_d1
+
+
+static double ratio(Bigint *a, Bigint *b)
+{
+ double da, db;
+ int32 k, ka, kb;
+
+ da = b2d(a, &ka);
+ db = b2d(b, &kb);
+ k = ka - kb + 32*(a->wds - b->wds);
+ if (k > 0)
+ set_word0(da, word0(da) + k*Exp_msk1);
+ else {
+ k = -k;
+ set_word0(db, word0(db) + k*Exp_msk1);
+ }
+ return da / db;
+}
+
+static CONST double
+tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+};
+
+static CONST double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+ 9007199254740992.e-256
+#else
+ 1e-256
+#endif
+ };
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+static int match(CONST char **sp, char *t)
+{
+ int c, d;
+ CONST char *s = *sp;
+
+ while(d = *t++) {
+ if ((c = *++s) >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != d)
+ return 0;
+ }
+ *sp = s + 1;
+ return 1;
+ }
+#endif /* INFNAN_CHECK */
+
+
+#ifdef JS_THREADSAFE
+static JSBool initialized = JS_FALSE;
+
+/* hacked replica of nspr _PR_InitDtoa */
+static void InitDtoa(void)
+{
+ freelist_lock = PR_NewLock();
+ p5s_lock = PR_NewLock();
+ initialized = JS_TRUE;
+}
+#endif
+
+void js_FinishDtoa(void)
+{
+ int count;
+ Bigint *temp;
+
+#ifdef JS_THREADSAFE
+ if (initialized == JS_TRUE) {
+ PR_DestroyLock(freelist_lock);
+ PR_DestroyLock(p5s_lock);
+ initialized = JS_FALSE;
+ }
+#endif
+
+ /* clear down the freelist array and p5s */
+
+ /* static Bigint *freelist[Kmax+1]; */
+ for (count = 0; count <= Kmax; count++) {
+ Bigint **listp = &freelist[count];
+ while ((temp = *listp) != NULL) {
+ *listp = temp->next;
+ free(temp);
+ }
+ freelist[count] = NULL;
+ }
+
+ /* static Bigint *p5s; */
+ while (p5s) {
+ temp = p5s;
+ p5s = p5s->next;
+ free(temp);
+ }
+}
+
+/* nspr2 watcom bug ifdef omitted */
+
+JS_FRIEND_API(double)
+JS_strtod(CONST char *s00, char **se, int *err)
+{
+ int32 scale;
+ int32 bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ CONST char *s, *s0, *s1;
+ double aadj, aadj1, adj, rv, rv0;
+ Long L;
+ ULong y, z;
+ Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+
+ SET_FPU();
+
+ *err = 0;
+
+ bb = bd = bs = delta = NULL;
+ sign = nz0 = nz = 0;
+ rv = 0.;
+
+ /* Locking for Balloc's shared buffers that will be used in this block */
+ ACQUIRE_DTOA_LOCK();
+
+ for(s = s00;;s++) switch(*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ s = s00;
+ goto ret;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+break2:
+
+ if (*s == '0') {
+ nz0 = 1;
+ while(*++s == '0') ;
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ y = z = 0;
+ for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10*y + c - '0';
+ else if (nd < 16)
+ z = 10*z + c - '0';
+ nd0 = nd;
+ if (c == '.') {
+ c = *++s;
+ if (!nd) {
+ for(; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+ nz++;
+ if (c -= '0') {
+ nf += nz;
+ for(i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 1)
+ z *= 10;
+ if (nd++ < 9)
+ y = 10*y + c;
+ else if (nd <= DBL_DIG + 1)
+ z = 10*z + c;
+ nz = 0;
+ }
+ }
+ }
+dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ s = s00;
+ goto ret;
+ }
+ s00 = s;
+ esign = 0;
+ switch(c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while(c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ s1 = s;
+ while((c = *++s) >= '0' && c <= '9')
+ L = 10*L + c - '0';
+ if (s - s1 > 8 || L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int32)L;
+ if (esign)
+ e = -e;
+ }
+ else
+ e = 0;
+ }
+ else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+ /* Check for Nan and Infinity */
+ switch(c) {
+ case 'i':
+ case 'I':
+ if (match(&s,"nfinity")) {
+ word0(rv) = 0x7ff00000;
+ word1(rv) = 0;
+ goto ret;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (match(&s, "an")) {
+ word0(rv) = NAN_WORD0;
+ word1(rv) = NAN_WORD1;
+ goto ret;
+ }
+ }
+#endif /* INFNAN_CHECK */
+ s = s00;
+ }
+ goto ret;
+ }
+ e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+ rv = y;
+ if (k > 9)
+ rv = tens[k - 9] * rv + z;
+ bd0 = 0;
+ if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+ && FLT_ROUNDS == 1
+#endif
+ ) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+ /* rv = */ rounded_product(rv, tens[e]);
+ goto ret;
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+ e -= i;
+ rv *= tens[i];
+ /* rv = */ rounded_product(rv, tens[e]);
+ goto ret;
+ }
+ }
+#ifndef Inaccurate_Divide
+ else if (e >= -Ten_pmax) {
+ /* rv = */ rounded_quotient(rv, tens[-e]);
+ goto ret;
+ }
+#endif
+ }
+ e1 += nd - k;
+
+ scale = 0;
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if ((i = e1 & 15) != 0)
+ rv *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+ *err = JS_DTOA_ERANGE;
+#ifdef __STDC__
+ rv = HUGE_VAL;
+#else
+ /* Can't trust HUGE_VAL */
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+#endif
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ e1 >>= 4;
+ for(j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ rv *= bigtens[j];
+ /* The last multiplication could overflow. */
+ set_word0(rv, word0(rv) - P*Exp_msk1);
+ rv *= bigtens[j];
+ if ((z = word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+ goto ovfl;
+ if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ set_word0(rv, Big0);
+ set_word1(rv, Big1);
+ }
+ else
+ set_word0(rv, word0(rv) + P*Exp_msk1);
+ }
+ }
+ else if (e1 < 0) {
+ e1 = -e1;
+ if ((i = e1 & 15) != 0)
+ rv /= tens[i];
+ if (e1 &= ~15) {
+ e1 >>= 4;
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+#ifdef Avoid_Underflow
+ if (e1 & Scale_Bit)
+ scale = P;
+ for(j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ rv *= tinytens[j];
+ if (scale && (j = P + 1 - ((word0(rv) & Exp_mask)
+ >> Exp_shift)) > 0) {
+ /* scaled rv is denormal; zap j low bits */
+ if (j >= 32) {
+ set_word1(rv, 0);
+ set_word0(rv, word0(rv) & (0xffffffff << (j-32)));
+ if (!word0(rv))
+ set_word0(rv, 1);
+ }
+ else
+ set_word1(rv, word1(rv) & (0xffffffff << j));
+ }
+#else
+ for(j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ rv *= tinytens[j];
+ /* The last multiplication could underflow. */
+ rv0 = rv;
+ rv *= tinytens[j];
+ if (!rv) {
+ rv = 2.*rv0;
+ rv *= tinytens[j];
+#endif
+ if (!rv) {
+ undfl:
+ rv = 0.;
+ *err = JS_DTOA_ERANGE;
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+#ifndef Avoid_Underflow
+ set_word0(rv, Tiny0);
+ set_word1(rv, Tiny1);
+ /* The refinement below will clean
+ * this approximation up.
+ */
+ }
+#endif
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bd0 = s2b(s0, nd0, nd, y);
+ if (!bd0)
+ goto nomem;
+
+ for(;;) {
+ bd = Balloc(bd0->k);
+ if (!bd)
+ goto nomem;
+ Bcopy(bd, bd0);
+ bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */
+ if (!bb)
+ goto nomem;
+ bs = i2b(1);
+ if (!bs)
+ goto nomem;
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ }
+ else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+#ifdef Sudden_Underflow
+ j = P + 1 - bbbits;
+#else
+#ifdef Avoid_Underflow
+ j = bbe - scale;
+#else
+ j = bbe;
+#endif
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#endif
+ bb2 += j;
+ bd2 += j;
+#ifdef Avoid_Underflow
+ bd2 += scale;
+#endif
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ if (!bs)
+ goto nomem;
+ bb1 = mult(bs, bb);
+ if (!bb1)
+ goto nomem;
+ Bfree(bb);
+ bb = bb1;
+ }
+ if (bb2 > 0) {
+ bb = lshift(bb, bb2);
+ if (!bb)
+ goto nomem;
+ }
+ if (bd5 > 0) {
+ bd = pow5mult(bd, bd5);
+ if (!bd)
+ goto nomem;
+ }
+ if (bd2 > 0) {
+ bd = lshift(bd, bd2);
+ if (!bd)
+ goto nomem;
+ }
+ if (bs2 > 0) {
+ bs = lshift(bs, bs2);
+ if (!bs)
+ goto nomem;
+ }
+ delta = diff(bb, bd);
+ if (!delta)
+ goto nomem;
+ dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask
+#ifdef Avoid_Underflow
+ || (word0(rv) & Exp_mask) <= Exp_msk1 + P*Exp_msk1
+#else
+ || (word0(rv) & Exp_mask) <= Exp_msk1
+#endif
+ ) {
+#ifdef Avoid_Underflow
+ if (!delta->x[0] && delta->wds == 1)
+ dsign = 2;
+#endif
+ break;
+ }
+ delta = lshift(delta,Log2P);
+ if (!delta)
+ goto nomem;
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+ && word1(rv) == 0xffffffff) {
+ /*boundary case -- increment exponent*/
+ set_word0(rv, (word0(rv) & Exp_mask) + Exp_msk1);
+ set_word1(rv, 0);
+#ifdef Avoid_Underflow
+ dsign = 0;
+#endif
+ break;
+ }
+ }
+ else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+#ifdef Avoid_Underflow
+ dsign = 2;
+#endif
+ drop_down:
+ /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow
+ L = word0(rv) & Exp_mask;
+ if (L <= Exp_msk1)
+ goto undfl;
+ L -= Exp_msk1;
+#else
+ L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif
+ set_word0(rv, L | Bndry_mask1);
+ set_word1(rv, 0xffffffff);
+ break;
+ }
+#ifndef ROUND_BIASED
+ if (!(word1(rv) & LSB))
+ break;
+#endif
+ if (dsign)
+ rv += ulp(rv);
+#ifndef ROUND_BIASED
+ else {
+ rv -= ulp(rv);
+#ifndef Sudden_Underflow
+ if (!rv)
+ goto undfl;
+#endif
+ }
+#ifdef Avoid_Underflow
+ dsign = 1 - dsign;
+#endif
+#endif
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = aadj1 = 1.;
+ else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+ if (word1(rv) == Tiny1 && !word0(rv))
+ goto undfl;
+#endif
+ aadj = 1.;
+ aadj1 = -1.;
+ }
+ else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2./FLT_RADIX)
+ aadj = 1./FLT_RADIX;
+ else
+ aadj *= 0.5;
+ aadj1 = -aadj;
+ }
+ }
+ else {
+ aadj *= 0.5;
+ aadj1 = dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+ switch(FLT_ROUNDS) {
+ case 2: /* towards +infinity */
+ aadj1 -= 0.5;
+ break;
+ case 0: /* towards 0 */
+ case 3: /* towards -infinity */
+ aadj1 += 0.5;
+ }
+#else
+ if (FLT_ROUNDS == 0)
+ aadj1 += 0.5;
+#endif
+ }
+ y = word0(rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+ rv0 = rv;
+ set_word0(rv, word0(rv) - P*Exp_msk1);
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+ if ((word0(rv) & Exp_mask) >=
+ Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+ if (word0(rv0) == Big0 && word1(rv0) == Big1)
+ goto ovfl;
+ set_word0(rv, Big0);
+ set_word1(rv, Big1);
+ goto cont;
+ }
+ else
+ set_word0(rv, word0(rv) + P*Exp_msk1);
+ }
+ else {
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ rv0 = rv;
+ set_word0(rv, word0(rv) + P*Exp_msk1);
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+ {
+ if (word0(rv0) == Tiny0
+ && word1(rv0) == Tiny1)
+ goto undfl;
+ set_word0(rv, Tiny0);
+ set_word1(rv, Tiny1);
+ goto cont;
+ }
+ else
+ set_word0(rv, word0(rv) - P*Exp_msk1);
+ }
+ else {
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+ }
+#else
+ /* Compute adj so that the IEEE rounding rules will
+ * correctly round rv + adj in some half-way cases.
+ * If rv * ulp(rv) is denormalized (i.e.,
+ * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+ * trouble from bits lost to denormalization;
+ * example: 1.2e-307 .
+ */
+#ifdef Avoid_Underflow
+ if (y <= P*Exp_msk1 && aadj > 1.)
+#else
+ if (y <= (P-1)*Exp_msk1 && aadj > 1.)
+#endif
+ {
+ aadj1 = (double)(int32)(aadj + 0.5);
+ if (!dsign)
+ aadj1 = -aadj1;
+ }
+#ifdef Avoid_Underflow
+ if (scale && y <= P*Exp_msk1)
+ set_word0(aadj1, word0(aadj1) + (P+1)*Exp_msk1 - y);
+#endif
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+#endif
+ }
+ z = word0(rv) & Exp_mask;
+#ifdef Avoid_Underflow
+ if (!scale)
+#endif
+ if (y == z) {
+ /* Can we stop now? */
+ L = (Long)aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ }
+ else if (aadj < .4999999/FLT_RADIX)
+ break;
+ }
+ cont:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ bb = bd = bs = delta = NULL;
+ }
+#ifdef Avoid_Underflow
+ if (scale) {
+ set_word0(rv0, Exp_1 - P*Exp_msk1);
+ set_word1(rv0, 0);
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1
+ && word1(rv) & 1
+ && dsign != 2) {
+ if (dsign) {
+#ifdef Sudden_Underflow
+ /* rv will be 0, but this would give the */
+ /* right result if only rv *= rv0 worked. */
+ set_word0(rv, word0(rv) + P*Exp_msk1);
+ set_word0(rv0, Exp_1 - 2*P*Exp_msk1);
+#endif
+ rv += ulp(rv);
+ }
+ else
+ set_word1(rv, word1(rv) & ~1);
+ }
+ rv *= rv0;
+ }
+#endif /* Avoid_Underflow */
+retfree:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ret:
+ RELEASE_DTOA_LOCK();
+ if (se)
+ *se = (char *)s;
+ rv0 = sign ? -rv : rv;
+ goto ret1;
+
+nomem:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ *err = JS_DTOA_ENOMEM;
+ rv0 = 0;
+
+ret1:
+ RESTORE_FPU();
+ return rv0;
+}
+
+
+/* Return floor(b/2^k) and set b to be the remainder. The returned quotient must be less than 2^32. */
+static uint32 quorem2(Bigint *b, int32 k)
+{
+ ULong mask;
+ ULong result;
+ ULong *bx, *bxe;
+ int32 w;
+ int32 n = k >> 5;
+ k &= 0x1F;
+ mask = (1<<k) - 1;
+
+ w = b->wds - n;
+ if (w <= 0)
+ return 0;
+ JS_ASSERT(w <= 2);
+ bx = b->x;
+ bxe = bx + n;
+ result = *bxe >> k;
+ *bxe &= mask;
+ if (w == 2) {
+ JS_ASSERT(!(bxe[1] & ~mask));
+ if (k)
+ result |= bxe[1] << (32 - k);
+ }
+ n++;
+ while (!*bxe && bxe != bx) {
+ n--;
+ bxe--;
+ }
+ b->wds = n;
+ return result;
+}
+
+/* Return floor(b/S) and set b to be the remainder. As added restrictions, b must not have
+ * more words than S, the most significant word of S must not start with a 1 bit, and the
+ * returned quotient must be less than 36. */
+static int32 quorem(Bigint *b, Bigint *S)
+{
+ int32 n;
+ ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+ ULLong borrow, carry, y, ys;
+#else
+ ULong borrow, carry, y, ys;
+ ULong si, z, zs;
+#endif
+
+ n = S->wds;
+ JS_ASSERT(b->wds <= n);
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ JS_ASSERT(*sxe <= 0x7FFFFFFF);
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+ JS_ASSERT(q < 36);
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef ULLong
+ ys = *sx++ * (ULLong)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & 1UL;
+ *bx++ = (ULong)(y & 0xffffffffUL);
+#else
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#endif
+ }
+ while(sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef ULLong
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & 1UL;
+ *bx++ = (ULong)(y & 0xffffffffUL);
+#else
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#endif
+ } while(sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return (int32)q;
+}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+/* Always emits at least one digit. */
+/* If biasUp is set, then rounding in modes 2 and 3 will round away from zero
+ * when the number is exactly halfway between two representable values. For example,
+ * rounding 2.5 to zero digits after the decimal point will return 3 and not 2.
+ * 2.49 will still round to 2, and 2.51 will still round to 3. */
+/* bufsize should be at least 20 for modes 0 and 1. For the other modes,
+ * bufsize should be two greater than the maximum number of output characters expected. */
+static JSBool
+js_dtoa(double d, int mode, JSBool biasUp, int ndigits,
+ int *decpt, int *sign, char **rve, char *buf, size_t bufsize)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4-9 should give the same return values as 2-3, i.e.,
+ 4 <= mode <= 9 ==> same return as mode
+ 2 + (mode & 1). These modes are mainly for
+ debugging; often they run slower but sometimes
+ faster than modes 2-3.
+ 4,5,8,9 ==> left-to-right digit generation.
+ 6-9 ==> don't try fast floating-point estimate
+ (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int32 bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick;
+ Long L;
+#ifndef Sudden_Underflow
+ int32 denorm;
+ ULong x;
+#endif
+ Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+ double d2, ds, eps;
+ char *s;
+ JSBool ok;
+
+ SET_FPU();
+
+ if (word0(d) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ set_word0(d, word0(d) & ~Sign_bit); /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+ if ((word0(d) & Exp_mask) == Exp_mask) {
+ /* Infinity or NaN */
+ *decpt = 9999;
+ s = !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN";
+ if ((s[0] == 'I' && bufsize < 9) || (s[0] == 'N' && bufsize < 4)) {
+ JS_ASSERT(JS_FALSE);
+/* JS_SetError(JS_BUFFER_OVERFLOW_ERROR, 0); */
+ ok = JS_FALSE;
+ goto ret2;
+ }
+ strcpy(buf, s);
+ if (rve) {
+ *rve = buf[3] ? buf + 8 : buf + 3;
+ JS_ASSERT(**rve == '\0');
+ }
+ ok = JS_TRUE;
+ goto ret2;
+ }
+
+ b = NULL; /* initialize for abort protection */
+ S = NULL;
+ mlo = mhi = NULL;
+
+ if (!d) {
+ no_digits:
+ *decpt = 1;
+ if (bufsize < 2) {
+ JS_ASSERT(JS_FALSE);
+/* JS_SetError(JS_BUFFER_OVERFLOW_ERROR, 0); */
+ ok = JS_FALSE;
+ goto ret2;
+ }
+ buf[0] = '0'; buf[1] = '\0'; /* copy "0" to buffer */
+ if (rve)
+ *rve = buf + 1;
+ /* We might have jumped to "no_digits" from below, so we need
+ * to be sure to free the potentially allocated Bigints to avoid
+ * memory leaks. */
+ Bfree(b);
+ Bfree(S);
+ if (mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ ok = JS_TRUE;
+ goto ret2;
+ }
+
+ b = d2b(d, &be, &bbits);
+ if (!b)
+ goto nomem;
+#ifdef Sudden_Underflow
+ i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+ if ((i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) {
+#endif
+ d2 = d;
+ set_word0(d2, word0(d2) & Frac_mask1);
+ set_word0(d2, word0(d2) | Exp_11);
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P-1) - 1);
+ x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) : word1(d) << (32 - i);
+ d2 = x;
+ set_word0(d2, word0(d2) - 31*Exp_msk1); /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ /* At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. */
+ ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+ k = (int32)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (d < tens[k])
+ k--;
+ k_check = 0;
+ }
+ /* At this point floor(log10(d)) <= k <= floor(log10(d))+1.
+ If k_check is zero, we're guaranteed that k = floor(log10(d)). */
+ j = bbits - i - 1;
+ /* At this point d = b/2^j, where b is an odd integer. */
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ /* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,
+ b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */
+ if (mode < 0 || mode > 9)
+ mode = 0;
+ try_quick = 1;
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ ilim = ilim1 = 0;
+ switch(mode) {
+ case 0:
+ case 1:
+ ilim = ilim1 = -1;
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ /* ilim is the maximum number of significant digits we want, based on k and ndigits. */
+ /* ilim1 is the maximum number of significant digits we want, based on k and ndigits,
+ when it turns out that k was computed too high by one. */
+
+ /* Ensure space for at least i+1 characters, including trailing null. */
+ if (bufsize <= (size_t)i) {
+ Bfree(b);
+ JS_ASSERT(JS_FALSE);
+ ok = JS_FALSE;
+ goto ret2;
+ }
+ s = buf;
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ d2 = d;
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ /* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ d /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for(; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ d /= ds;
+ }
+ else if ((j1 = -k) != 0) {
+ d *= tens[j1 & 0xf];
+ for(j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ d *= bigtens[i];
+ }
+ }
+ /* Check that k was computed correctly. */
+ if (k_check && d < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ d *= 10.;
+ ieps++;
+ }
+ /* eps bounds the cumulative error. */
+ eps = ieps*d + 7.;
+ set_word0(eps, word0(eps) - (P-1)*Exp_msk1);
+ if (ilim == 0) {
+ S = mhi = 0;
+ d -= 5.;
+ if (d > eps)
+ goto one_digit;
+ if (d < -eps)
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ eps = 0.5/tens[ilim-1] - eps;
+ for(i = 0;;) {
+ L = (Long)d;
+ d -= L;
+ *s++ = '0' + (char)L;
+ if (d < eps)
+ goto ret1;
+ if (1. - d < eps)
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ eps *= 10.;
+ d *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ eps *= tens[ilim-1];
+ for(i = 1;; i++, d *= 10.) {
+ L = (Long)d;
+ d -= L;
+ *s++ = '0' + (char)L;
+ if (i == ilim) {
+ if (d > 0.5 + eps)
+ goto bump_up;
+ else if (d < 0.5 - eps) {
+ while(*--s == '0') ;
+ s++;
+ goto ret1;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+ fast_failed:
+ s = buf;
+ d = d2;
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds))
+ goto no_digits;
+ goto one_digit;
+ }
+ for(i = 1;; i++) {
+ L = (Long) (d / ds);
+ d -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (d < 0) {
+ L--;
+ d += ds;
+ }
+#endif
+ *s++ = '0' + (char)L;
+ if (i == ilim) {
+ d += d;
+ if ((d > ds) || (d == ds && (L & 1 || biasUp))) {
+ bump_up:
+ while(*--s == '9')
+ if (s == buf) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ if (!(d *= 10.))
+ break;
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ if (leftright) {
+ if (mode < 2) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+ 1 + P - bbits;
+ /* i is 1 plus the number of trailing zero bits in d's significand. Thus,
+ (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */
+ }
+ else {
+ j = ilim - 1;
+ if (m5 >= j)
+ m5 -= j;
+ else {
+ s5 += j -= m5;
+ b5 += j;
+ m5 = 0;
+ }
+ if ((i = ilim) < 0) {
+ m2 -= i;
+ i = 0;
+ }
+ /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */
+ }
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ if (!mhi)
+ goto nomem;
+ /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or
+ input (when mode < 2) significant digit, divided by 10^k. */
+ }
+ /* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in
+ b2, m2, and s2 without changing the equalities. */
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+
+ /* Fold b5 into b and m5 into mhi. */
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ if (!mhi)
+ goto nomem;
+ b1 = mult(mhi, b);
+ if (!b1)
+ goto nomem;
+ Bfree(b);
+ b = b1;
+ }
+ if ((j = b5 - m5) != 0) {
+ b = pow5mult(b, j);
+ if (!b)
+ goto nomem;
+ }
+ }
+ else {
+ b = pow5mult(b, b5);
+ if (!b)
+ goto nomem;
+ }
+ }
+ /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
+ (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */
+
+ S = i2b(1);
+ if (!S)
+ goto nomem;
+ if (s5 > 0) {
+ S = pow5mult(S, s5);
+ if (!S)
+ goto nomem;
+ }
+ /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
+ (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */
+
+ /* Check for special case that d is a normalized power of 2. */
+ spec_case = 0;
+ if (mode < 2) {
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & (Exp_mask & Exp_mask << 1)
+#endif
+ ) {
+ /* The special case. Here we want to be within a quarter of the last input
+ significant digit instead of one half of it when the decimal output string's value is less than d. */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+ if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
+ i = 32 - i;
+ /* i is the number of leading zero bits in the most significant word of S*2^s2. */
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */
+ if (b2 > 0) {
+ b = lshift(b, b2);
+ if (!b)
+ goto nomem;
+ }
+ if (s2 > 0) {
+ S = lshift(S, s2);
+ if (!S)
+ goto nomem;
+ }
+ /* Now we have d/10^k = b/S and
+ (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (!b)
+ goto nomem;
+ if (leftright) {
+ mhi = multadd(mhi, 10, 0);
+ if (!mhi)
+ goto nomem;
+ }
+ ilim = ilim1;
+ }
+ }
+ /* At this point 1 <= d/10^k = b/S < 10. */
+
+ if (ilim <= 0 && mode > 2) {
+ /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.
+ Output either zero or the minimum nonzero output depending on which is closer to d. */
+ if (ilim < 0)
+ goto no_digits;
+ S = multadd(S,5,0);
+ if (!S)
+ goto nomem;
+ i = cmp(b,S);
+ if (i < 0 || (i == 0 && !biasUp)) {
+ /* Always emit at least one digit. If the number appears to be zero
+ using the current mode, then emit one '0' digit and set decpt to 1. */
+ /*no_digits:
+ k = -1 - ndigits;
+ goto ret; */
+ goto no_digits;
+ }
+ one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0) {
+ mhi = lshift(mhi, m2);
+ if (!mhi)
+ goto nomem;
+ }
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ if (!mhi)
+ goto nomem;
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ if (!mhi)
+ goto nomem;
+ }
+ /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */
+ /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */
+
+ for(i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ /* j is b/S compared with mlo/S. */
+ delta = diff(S, mhi);
+ if (!delta)
+ goto nomem;
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+ /* j1 is b/S compared with 1 - mhi/S. */
+#ifndef ROUND_BIASED
+ if (j1 == 0 && !mode && !(word1(d) & 1)) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+ *s++ = (char)dig;
+ goto ret;
+ }
+#endif
+ if ((j < 0) || (j == 0 && !mode
+#ifndef ROUND_BIASED
+ && !(word1(d) & 1)
+#endif
+ )) {
+ if (j1 > 0) {
+ /* Either dig or dig+1 would work here as the least significant decimal digit.
+ Use whichever would produce a decimal value closer to d. */
+ b = lshift(b, 1);
+ if (!b)
+ goto nomem;
+ j1 = cmp(b, S);
+ if (((j1 > 0) || (j1 == 0 && (dig & 1 || biasUp)))
+ && (dig++ == '9'))
+ goto round_9_up;
+ }
+ *s++ = (char)dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+ if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *s++ = (char)dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (!b)
+ goto nomem;
+ if (mlo == mhi) {
+ mlo = mhi = multadd(mhi, 10, 0);
+ if (!mhi)
+ goto nomem;
+ }
+ else {
+ mlo = multadd(mlo, 10, 0);
+ if (!mlo)
+ goto nomem;
+ mhi = multadd(mhi, 10, 0);
+ if (!mhi)
+ goto nomem;
+ }
+ }
+ }
+ else
+ for(i = 1;; i++) {
+ *s++ = (char)(dig = quorem(b,S) + '0');
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (!b)
+ goto nomem;
+ }
+
+ /* Round off last digit */
+
+ b = lshift(b, 1);
+ if (!b)
+ goto nomem;
+ j = cmp(b, S);
+ if ((j > 0) || (j == 0 && (dig & 1 || biasUp))) {
+ roundoff:
+ while(*--s == '9')
+ if (s == buf) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ else {
+ /* Strip trailing zeros */
+ while(*--s == '0') ;
+ s++;
+ }
+ ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ ret1:
+ Bfree(b);
+ JS_ASSERT(s < buf + bufsize);
+ *s = '\0';
+ if (rve)
+ *rve = s;
+ *decpt = k + 1;
+ ok = JS_TRUE;
+ goto ret2;
+
+nomem:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ Bfree(b);
+ ok = JS_FALSE;
+
+ret2:
+ RESTORE_FPU();
+ return ok;
+}
+
+
+/* Mapping of JSDToStrMode -> js_dtoa mode */
+static const int dtoaModes[] = {
+ 0, /* DTOSTR_STANDARD */
+ 0, /* DTOSTR_STANDARD_EXPONENTIAL, */
+ 3, /* DTOSTR_FIXED, */
+ 2, /* DTOSTR_EXPONENTIAL, */
+ 2}; /* DTOSTR_PRECISION */
+
+JS_FRIEND_API(char *)
+JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double d)
+{
+ int decPt; /* Position of decimal point relative to first digit returned by js_dtoa */
+ int sign; /* Nonzero if the sign bit was set in d */
+ int nDigits; /* Number of significand digits returned by js_dtoa */
+ char *numBegin = buffer+2; /* Pointer to the digits returned by js_dtoa; the +2 leaves space for */
+ /* the sign and/or decimal point */
+ char *numEnd; /* Pointer past the digits returned by js_dtoa */
+ JSBool dtoaRet;
+
+ JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL ? DTOSTR_STANDARD_BUFFER_SIZE :
+ DTOSTR_VARIABLE_BUFFER_SIZE(precision)));
+
+ if (mode == DTOSTR_FIXED && (d >= 1e21 || d <= -1e21))
+ mode = DTOSTR_STANDARD; /* Change mode here rather than below because the buffer may not be large enough to hold a large integer. */
+
+ /* Locking for Balloc's shared buffers */
+ ACQUIRE_DTOA_LOCK();
+ dtoaRet = js_dtoa(d, dtoaModes[mode], mode >= DTOSTR_FIXED, precision, &decPt, &sign, &numEnd, numBegin, bufferSize-2);
+ RELEASE_DTOA_LOCK();
+ if (!dtoaRet)
+ return 0;
+
+ nDigits = numEnd - numBegin;
+
+ /* If Infinity, -Infinity, or NaN, return the string regardless of the mode. */
+ if (decPt != 9999) {
+ JSBool exponentialNotation = JS_FALSE;
+ int minNDigits = 0; /* Minimum number of significand digits required by mode and precision */
+ char *p;
+ char *q;
+
+ switch (mode) {
+ case DTOSTR_STANDARD:
+ if (decPt < -5 || decPt > 21)
+ exponentialNotation = JS_TRUE;
+ else
+ minNDigits = decPt;
+ break;
+
+ case DTOSTR_FIXED:
+ if (precision >= 0)
+ minNDigits = decPt + precision;
+ else
+ minNDigits = decPt;
+ break;
+
+ case DTOSTR_EXPONENTIAL:
+ JS_ASSERT(precision > 0);
+ minNDigits = precision;
+ /* Fall through */
+ case DTOSTR_STANDARD_EXPONENTIAL:
+ exponentialNotation = JS_TRUE;
+ break;
+
+ case DTOSTR_PRECISION:
+ JS_ASSERT(precision > 0);
+ minNDigits = precision;
+ if (decPt < -5 || decPt > precision)
+ exponentialNotation = JS_TRUE;
+ break;
+ }
+
+ /* If the number has fewer than minNDigits, pad it with zeros at the end */
+ if (nDigits < minNDigits) {
+ p = numBegin + minNDigits;
+ nDigits = minNDigits;
+ do {
+ *numEnd++ = '0';
+ } while (numEnd != p);
+ *numEnd = '\0';
+ }
+
+ if (exponentialNotation) {
+ /* Insert a decimal point if more than one significand digit */
+ if (nDigits != 1) {
+ numBegin--;
+ numBegin[0] = numBegin[1];
+ numBegin[1] = '.';
+ }
+ JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1);
+ } else if (decPt != nDigits) {
+ /* Some kind of a fraction in fixed notation */
+ JS_ASSERT(decPt <= nDigits);
+ if (decPt > 0) {
+ /* dd...dd . dd...dd */
+ p = --numBegin;
+ do {
+ *p = p[1];
+ p++;
+ } while (--decPt);
+ *p = '.';
+ } else {
+ /* 0 . 00...00dd...dd */
+ p = numEnd;
+ numEnd += 1 - decPt;
+ q = numEnd;
+ JS_ASSERT(numEnd < buffer + bufferSize);
+ *numEnd = '\0';
+ while (p != numBegin)
+ *--q = *--p;
+ for (p = numBegin + 1; p != q; p++)
+ *p = '0';
+ *numBegin = '.';
+ *--numBegin = '0';
+ }
+ }
+ }
+
+ /* If negative and neither -0.0 nor NaN, output a leading '-'. */
+ if (sign &&
+ !(word0(d) == Sign_bit && word1(d) == 0) &&
+ !((word0(d) & Exp_mask) == Exp_mask &&
+ (word1(d) || (word0(d) & Frac_mask)))) {
+ *--numBegin = '-';
+ }
+ return numBegin;
+}
+
+
+/* Let b = floor(b / divisor), and return the remainder. b must be nonnegative.
+ * divisor must be between 1 and 65536.
+ * This function cannot run out of memory. */
+static uint32
+divrem(Bigint *b, uint32 divisor)
+{
+ int32 n = b->wds;
+ uint32 remainder = 0;
+ ULong *bx;
+ ULong *bp;
+
+ JS_ASSERT(divisor > 0 && divisor <= 65536);
+
+ if (!n)
+ return 0; /* b is zero */
+ bx = b->x;
+ bp = bx + n;
+ do {
+ ULong a = *--bp;
+ ULong dividend = remainder << 16 | a >> 16;
+ ULong quotientHi = dividend / divisor;
+ ULong quotientLo;
+
+ remainder = dividend - quotientHi*divisor;
+ JS_ASSERT(quotientHi <= 0xFFFF && remainder < divisor);
+ dividend = remainder << 16 | (a & 0xFFFF);
+ quotientLo = dividend / divisor;
+ remainder = dividend - quotientLo*divisor;
+ JS_ASSERT(quotientLo <= 0xFFFF && remainder < divisor);
+ *bp = quotientHi << 16 | quotientLo;
+ } while (bp != bx);
+ /* Decrease the size of the number if its most significant word is now zero. */
+ if (bx[n-1] == 0)
+ b->wds--;
+ return remainder;
+}
+
+
+/* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
+ * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of
+ * the output string and malloc fewer bytes depending on d and base, but why bother? */
+#define DTOBASESTR_BUFFER_SIZE 1078
+#define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit)))
+
+JS_FRIEND_API(char *)
+JS_dtobasestr(int base, double d)
+{
+ char *buffer; /* The output string */
+ char *p; /* Pointer to current position in the buffer */
+ char *pInt; /* Pointer to the beginning of the integer part of the string */
+ char *q;
+ uint32 digit;
+ double di; /* d truncated to an integer */
+ double df; /* The fractional part of d */
+
+ JS_ASSERT(base >= 2 && base <= 36);
+
+ buffer = (char*) malloc(DTOBASESTR_BUFFER_SIZE);
+ if (buffer) {
+ p = buffer;
+ if (d < 0.0
+#if defined(XP_WIN) || defined(XP_OS2)
+ && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */
+#endif
+ ) {
+ *p++ = '-';
+ d = -d;
+ }
+
+ /* Check for Infinity and NaN */
+ if ((word0(d) & Exp_mask) == Exp_mask) {
+ strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN");
+ return buffer;
+ }
+
+ /* Locking for Balloc's shared buffers */
+ ACQUIRE_DTOA_LOCK();
+
+ /* Output the integer part of d with the digits in reverse order. */
+ pInt = p;
+ di = fd_floor(d);
+ if (di <= 4294967295.0) {
+ uint32 n = (uint32)di;
+ if (n)
+ do {
+ uint32 m = n / base;
+ digit = n - m*base;
+ n = m;
+ JS_ASSERT(digit < (uint32)base);
+ *p++ = BASEDIGIT(digit);
+ } while (n);
+ else *p++ = '0';
+ } else {
+ int32 e;
+ int32 bits; /* Number of significant bits in di; not used. */
+ Bigint *b = d2b(di, &e, &bits);
+ if (!b)
+ goto nomem1;
+ b = lshift(b, e);
+ if (!b) {
+ nomem1:
+ Bfree(b);
+ return NULL;
+ }
+ do {
+ digit = divrem(b, base);
+ JS_ASSERT(digit < (uint32)base);
+ *p++ = BASEDIGIT(digit);
+ } while (b->wds);
+ Bfree(b);
+ }
+ /* Reverse the digits of the integer part of d. */
+ q = p-1;
+ while (q > pInt) {
+ char ch = *pInt;
+ *pInt++ = *q;
+ *q-- = ch;
+ }
+
+ df = d - di;
+ if (df != 0.0) {
+ /* We have a fraction. */
+ int32 e, bbits, s2, done;
+ Bigint *b, *s, *mlo, *mhi;
+
+ b = s = mlo = mhi = NULL;
+
+ *p++ = '.';
+ b = d2b(df, &e, &bbits);
+ if (!b) {
+ nomem2:
+ Bfree(b);
+ Bfree(s);
+ if (mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ return NULL;
+ }
+ JS_ASSERT(e < 0);
+ /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */
+
+ s2 = -(int32)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1);
+#ifndef Sudden_Underflow
+ if (!s2)
+ s2 = -1;
+#endif
+ s2 += Bias + P;
+ /* 1/2^s2 = (nextDouble(d) - d)/2 */
+ JS_ASSERT(-s2 < e);
+ mlo = i2b(1);
+ if (!mlo)
+ goto nomem2;
+ mhi = mlo;
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & (Exp_mask & Exp_mask << 1)
+#endif
+ ) {
+ /* The special case. Here we want to be within a quarter of the last input
+ significant digit instead of one half of it when the output string's value is less than d. */
+ s2 += Log2P;
+ mhi = i2b(1<<Log2P);
+ if (!mhi)
+ goto nomem2;
+ }
+ b = lshift(b, e + s2);
+ if (!b)
+ goto nomem2;
+ s = i2b(1);
+ if (!s)
+ goto nomem2;
+ s = lshift(s, s2);
+ if (!s)
+ goto nomem2;
+ /* At this point we have the following:
+ * s = 2^s2;
+ * 1 > df = b/2^s2 > 0;
+ * (d - prevDouble(d))/2 = mlo/2^s2;
+ * (nextDouble(d) - d)/2 = mhi/2^s2. */
+
+ done = JS_FALSE;
+ do {
+ int32 j, j1;
+ Bigint *delta;
+
+ b = multadd(b, base, 0);
+ if (!b)
+ goto nomem2;
+ digit = quorem2(b, s2);
+ if (mlo == mhi) {
+ mlo = mhi = multadd(mlo, base, 0);
+ if (!mhi)
+ goto nomem2;
+ }
+ else {
+ mlo = multadd(mlo, base, 0);
+ if (!mlo)
+ goto nomem2;
+ mhi = multadd(mhi, base, 0);
+ if (!mhi)
+ goto nomem2;
+ }
+
+ /* Do we yet have the shortest string that will round to d? */
+ j = cmp(b, mlo);
+ /* j is b/2^s2 compared with mlo/2^s2. */
+ delta = diff(s, mhi);
+ if (!delta)
+ goto nomem2;
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+ /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
+
+#ifndef ROUND_BIASED
+ if (j1 == 0 && !(word1(d) & 1)) {
+ if (j > 0)
+ digit++;
+ done = JS_TRUE;
+ } else
+#endif
+ if (j < 0 || (j == 0
+#ifndef ROUND_BIASED
+ && !(word1(d) & 1)
+#endif
+ )) {
+ if (j1 > 0) {
+ /* Either dig or dig+1 would work here as the least significant digit.
+ Use whichever would produce an output value closer to d. */
+ b = lshift(b, 1);
+ if (!b)
+ goto nomem2;
+ j1 = cmp(b, s);
+ if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output
+ * such as 3.5 in base 3. */
+ digit++;
+ }
+ done = JS_TRUE;
+ } else if (j1 > 0) {
+ digit++;
+ done = JS_TRUE;
+ }
+ JS_ASSERT(digit < (uint32)base);
+ *p++ = BASEDIGIT(digit);
+ } while (!done);
+ Bfree(b);
+ Bfree(s);
+ if (mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE);
+ *p = '\0';
+ RELEASE_DTOA_LOCK();
+ }
+ return buffer;
+}
diff --git a/src/dom/js/jsdtoa.h b/src/dom/js/jsdtoa.h
new file mode 100644
index 000000000..409f45454
--- /dev/null
+++ b/src/dom/js/jsdtoa.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsdtoa_h___
+#define jsdtoa_h___
+/*
+ * Public interface to portable double-precision floating point to string
+ * and back conversion package.
+ */
+
+#include "jscompat.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * JS_strtod() returns as a double-precision floating-point number
+ * the value represented by the character string pointed to by
+ * s00. The string is scanned up to the first unrecognized
+ * character.
+ * If the value of se is not (char **)NULL, a pointer to
+ * the character terminating the scan is returned in the location pointed
+ * to by se. If no number can be formed, se is set to s00r, and
+ * zero is returned.
+ *
+ * *err is set to zero on success; it's set to JS_DTOA_ERANGE on range
+ * errors and JS_DTOA_ENOMEM on memory failure.
+ */
+#define JS_DTOA_ERANGE 1
+#define JS_DTOA_ENOMEM 2
+JS_FRIEND_API(double)
+JS_strtod(const char *s00, char **se, int *err);
+
+/*
+ * Modes for converting floating-point numbers to strings.
+ *
+ * Some of the modes can round-trip; this means that if the number is converted to
+ * a string using one of these mode and then converted back to a number, the result
+ * will be identical to the original number (except that, due to ECMA, -0 will get converted
+ * to +0). These round-trip modes return the minimum number of significand digits that
+ * permit the round trip.
+ *
+ * Some of the modes take an integer parameter <precision>.
+ */
+/* NB: Keep this in sync with number_constants[]. */
+typedef enum JSDToStrMode {
+ DTOSTR_STANDARD, /* Either fixed or exponential format; round-trip */
+ DTOSTR_STANDARD_EXPONENTIAL, /* Always exponential format; round-trip */
+ DTOSTR_FIXED, /* Round to <precision> digits after the decimal point; exponential if number is large */
+ DTOSTR_EXPONENTIAL, /* Always exponential format; <precision> significant digits */
+ DTOSTR_PRECISION /* Either fixed or exponential format; <precision> significant digits */
+} JSDToStrMode;
+
+
+/* Maximum number of characters (including trailing null) that a DTOSTR_STANDARD or DTOSTR_STANDARD_EXPONENTIAL
+ * conversion can produce. This maximum is reached for a number like -0.0000012345678901234567. */
+#define DTOSTR_STANDARD_BUFFER_SIZE 26
+
+/* Maximum number of characters (including trailing null) that one of the other conversions
+ * can produce. This maximum is reached for TO_FIXED, which can generate up to 21 digits before the decimal point. */
+#define DTOSTR_VARIABLE_BUFFER_SIZE(precision) ((precision)+24 > DTOSTR_STANDARD_BUFFER_SIZE ? (precision)+24 : DTOSTR_STANDARD_BUFFER_SIZE)
+
+/*
+ * Convert dval according to the given mode and return a pointer to the resulting ASCII string.
+ * The result is held somewhere in buffer, but not necessarily at the beginning. The size of
+ * buffer is given in bufferSize, and must be at least as large as given by the above macros.
+ *
+ * Return NULL if out of memory.
+ */
+JS_FRIEND_API(char *)
+JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dval);
+
+/*
+ * Convert d to a string in the given base. The integral part of d will be printed exactly
+ * in that base, regardless of how large it is, because there is no exponential notation for non-base-ten
+ * numbers. The fractional part will be rounded to as few digits as possible while still preserving
+ * the round-trip property (analogous to that of printing decimal numbers). In other words, if one were
+ * to read the resulting string in via a hypothetical base-number-reading routine that rounds to the nearest
+ * IEEE double (and to an even significand if there are two equally near doubles), then the result would
+ * equal d (except for -0.0, which converts to "0", and NaN, which is not equal to itself).
+ *
+ * Return NULL if out of memory. If the result is not NULL, it must be released via free().
+ */
+JS_FRIEND_API(char *)
+JS_dtobasestr(int base, double d);
+
+/*
+ * Clean up any persistent RAM allocated during the execution of DtoA
+ * routines, and remove any locks that might have been created.
+ */
+extern void js_FinishDtoa(void);
+
+JS_END_EXTERN_C
+
+#endif /* jsdtoa_h___ */
diff --git a/src/dom/js/jsemit.c b/src/dom/js/jsemit.c
new file mode 100644
index 000000000..13e105c07
--- /dev/null
+++ b/src/dom/js/jsemit.c
@@ -0,0 +1,4471 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS bytecode generation.
+ */
+#include "jsstddef.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsbit.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsemit.h"
+#include "jsfun.h"
+#include "jsnum.h"
+#include "jsopcode.h"
+#include "jsparse.h"
+#include "jsscan.h"
+#include "jsscope.h"
+#include "jsscript.h"
+
+/* Allocation chunk counts, must be powers of two in general. */
+#define BYTECODE_CHUNK 256 /* code allocation increment */
+#define SRCNOTE_CHUNK 64 /* initial srcnote allocation increment */
+#define TRYNOTE_CHUNK 64 /* trynote allocation increment */
+
+/* Macros to compute byte sizes from typed element counts. */
+#define BYTECODE_SIZE(n) ((n) * sizeof(jsbytecode))
+#define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote))
+#define TRYNOTE_SIZE(n) ((n) * sizeof(JSTryNote))
+
+JS_FRIEND_API(JSBool)
+js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
+ JSArenaPool *codePool, JSArenaPool *notePool,
+ const char *filename, uintN lineno,
+ JSPrincipals *principals)
+{
+ memset(cg, 0, sizeof *cg);
+ TREE_CONTEXT_INIT(&cg->treeContext);
+ cg->treeContext.flags |= TCF_COMPILING;
+ cg->codePool = codePool;
+ cg->notePool = notePool;
+ cg->codeMark = JS_ARENA_MARK(codePool);
+ cg->noteMark = JS_ARENA_MARK(notePool);
+ cg->tempMark = JS_ARENA_MARK(&cx->tempPool);
+ cg->current = &cg->main;
+ cg->filename = filename;
+ cg->firstLine = cg->prolog.currentLine = cg->main.currentLine = lineno;
+ cg->principals = principals;
+ ATOM_LIST_INIT(&cg->atomList);
+ cg->prolog.noteMask = cg->main.noteMask = SRCNOTE_CHUNK - 1;
+ return JS_TRUE;
+}
+
+JS_FRIEND_API(void)
+js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg)
+{
+ TREE_CONTEXT_FINISH(&cg->treeContext);
+ JS_ARENA_RELEASE(cg->codePool, cg->codeMark);
+ JS_ARENA_RELEASE(cg->notePool, cg->noteMark);
+ JS_ARENA_RELEASE(&cx->tempPool, cg->tempMark);
+}
+
+static ptrdiff_t
+EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
+{
+ jsbytecode *base, *limit, *next;
+ ptrdiff_t offset, length;
+ size_t incr, size;
+
+ base = CG_BASE(cg);
+ next = CG_NEXT(cg);
+ limit = CG_LIMIT(cg);
+ offset = PTRDIFF(next, base, jsbytecode);
+ if (next + delta > limit) {
+ length = offset + delta;
+ length = (length <= BYTECODE_CHUNK)
+ ? BYTECODE_CHUNK
+ : JS_BIT(JS_CeilingLog2(length));
+ incr = BYTECODE_SIZE(length);
+ if (!base) {
+ JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr);
+ } else {
+ size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode));
+ incr -= size;
+ JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
+ }
+ if (!base) {
+ JS_ReportOutOfMemory(cx);
+ return -1;
+ }
+ CG_BASE(cg) = base;
+ CG_LIMIT(cg) = base + length;
+ CG_NEXT(cg) = base + offset;
+ }
+ return offset;
+}
+
+static void
+UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
+{
+ jsbytecode *pc;
+ const JSCodeSpec *cs;
+ intN nuses;
+
+ pc = CG_CODE(cg, target);
+ cs = &js_CodeSpec[pc[0]];
+ nuses = cs->nuses;
+ if (nuses < 0)
+ nuses = 2 + GET_ARGC(pc); /* stack: fun, this, [argc arguments] */
+ cg->stackDepth -= nuses;
+ if (cg->stackDepth < 0) {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%d", target);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_STACK_UNDERFLOW,
+ cg->filename ? cg->filename : "stdin", numBuf);
+ }
+ cg->stackDepth += cs->ndefs;
+ if ((uintN)cg->stackDepth > cg->maxStackDepth)
+ cg->maxStackDepth = cg->stackDepth;
+}
+
+ptrdiff_t
+js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op)
+{
+ ptrdiff_t offset = EmitCheck(cx, cg, op, 1);
+
+ if (offset >= 0) {
+ *CG_NEXT(cg)++ = (jsbytecode)op;
+ UpdateDepth(cx, cg, offset);
+ }
+ return offset;
+}
+
+ptrdiff_t
+js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1)
+{
+ ptrdiff_t offset = EmitCheck(cx, cg, op, 2);
+
+ if (offset >= 0) {
+ jsbytecode *next = CG_NEXT(cg);
+ next[0] = (jsbytecode)op;
+ next[1] = op1;
+ CG_NEXT(cg) = next + 2;
+ UpdateDepth(cx, cg, offset);
+ }
+ return offset;
+}
+
+ptrdiff_t
+js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
+ jsbytecode op2)
+{
+ ptrdiff_t offset = EmitCheck(cx, cg, op, 3);
+
+ if (offset >= 0) {
+ jsbytecode *next = CG_NEXT(cg);
+ next[0] = (jsbytecode)op;
+ next[1] = op1;
+ next[2] = op2;
+ CG_NEXT(cg) = next + 3;
+ UpdateDepth(cx, cg, offset);
+ }
+ return offset;
+}
+
+ptrdiff_t
+js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra)
+{
+ ptrdiff_t length = 1 + (ptrdiff_t)extra;
+ ptrdiff_t offset = EmitCheck(cx, cg, op, length);
+
+ if (offset >= 0) {
+ jsbytecode *next = CG_NEXT(cg);
+ *next = (jsbytecode)op;
+ memset(next + 1, 0, BYTECODE_SIZE(extra));
+ CG_NEXT(cg) = next + length;
+ UpdateDepth(cx, cg, offset);
+ }
+ return offset;
+}
+
+/* XXX too many "... statement" L10N gaffes below -- fix via js.msg! */
+const char js_with_statement_str[] = "with statement";
+
+static const char *statementName[] = {
+ "block", /* BLOCK */
+ "label statement", /* LABEL */
+ "if statement", /* IF */
+ "else statement", /* ELSE */
+ "switch statement", /* SWITCH */
+ js_with_statement_str, /* WITH */
+ "try statement", /* TRY */
+ "catch block", /* CATCH */
+ "finally statement", /* FINALLY */
+ "do loop", /* DO_LOOP */
+ "for loop", /* FOR_LOOP */
+ "for/in loop", /* FOR_IN_LOOP */
+ "while loop", /* WHILE_LOOP */
+};
+
+static const char *
+StatementName(JSCodeGenerator *cg)
+{
+ if (!cg->treeContext.topStmt)
+ return "script";
+ return statementName[cg->treeContext.topStmt->type];
+}
+
+static void
+ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg)
+{
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET,
+ StatementName(cg));
+}
+
+/**
+ Span-dependent instructions in JS bytecode consist of the jump (JOF_JUMP)
+ and switch (JOF_LOOKUPSWITCH, JOF_TABLESWITCH) format opcodes, subdivided
+ into unconditional (gotos and gosubs), and conditional jumps or branches
+ (which pop a value, test it, and jump depending on its value). Most jumps
+ have just one immediate operand, a signed offset from the jump opcode's pc
+ to the target bytecode. The lookup and table switch opcodes may contain
+ many jump offsets.
+
+ Mozilla bug #80981 (http://bugzilla.mozilla.org/show_bug.cgi?id=80981) was
+ fixed by adding extended "X" counterparts to the opcodes/formats (NB: X is
+ suffixed to prefer JSOP_ORX thereby avoiding a JSOP_XOR name collision for
+ the extended form of the JSOP_OR branch opcode). The unextended or short
+ formats have 16-bit signed immediate offset operands, the extended or long
+ formats have 32-bit signed immediates. The span-dependency problem consists
+ of selecting as few long instructions as possible, or about as few -- since
+ jumps can span other jumps, extending one jump may cause another to need to
+ be extended.
+
+ Most JS scripts are short, so need no extended jumps. We optimize for this
+ case by generating short jumps until we know a long jump is needed. After
+ that point, we keep generating short jumps, but each jump's 16-bit immediate
+ offset operand is actually an unsigned index into cg->spanDeps, an array of
+ JSSpanDep structs. Each struct tells the top offset in the script of the
+ opcode, the "before" offset of the jump (which will be the same as top for
+ simplex jumps, but which will index further into the bytecode array for a
+ non-initial jump offset in a lookup or table switch), the after "offset"
+ adjusted during span-dependent instruction selection (initially the same
+ value as the "before" offset), and the jump target (more below).
+
+ Since we generate cg->spanDeps lazily, from within js_SetJumpOffset, we must
+ ensure that all bytecode generated so far can be inspected to discover where
+ the jump offset immediate operands lie within CG_CODE(cg). But the bonus is
+ that we generate span-dependency records sorted by their offsets, so we can
+ binary-search when trying to find a JSSpanDep for a given bytecode offset,
+ or the nearest JSSpanDep at or above a given pc.
+
+ To avoid limiting scripts to 64K jumps, if the cg->spanDeps index overflows
+ 65534, we store SPANDEP_INDEX_HUGE in the jump's immediate operand. This
+ tells us that we need to binary-search for the cg->spanDeps entry by the
+ jump opcode's bytecode offset (sd->before).
+
+ Jump targets need to be maintained in a data structure that lets us look
+ up an already-known target by its address (jumps may have a common target),
+ and that also lets us update the addresses (script-relative, a.k.a. absolute
+ offsets) of targets that come after a jump target (for when a jump below
+ that target needs to be extended). We use an AVL tree, implemented using
+ recursion, but with some tricky optimizations to its height-balancing code
+ (see http://www.enteract.com/~bradapp/ftp/src/libs/C++/AvlTrees.html).
+
+ A final wrinkle: backpatch chains are linked by jump-to-jump offsets with
+ positive sign, even though they link "backward" (i.e., toward lower bytecode
+ address). We don't want to waste space and search time in the AVL tree for
+ such temporary backpatch deltas, so we use a single-bit wildcard scheme to
+ tag true JSJumpTarget pointers and encode untagged, signed (positive) deltas
+ in JSSpanDep.target pointers, depending on whether the JSSpanDep has a known
+ target, or is still awaiting backpatching.
+
+ Note that backpatch chains would present a problem for BuildSpanDepTable,
+ which inspects bytecode to build cg->spanDeps on demand, when the first
+ short jump offset overflows. To solve this temporary problem, we emit a
+ proxy bytecode (JSOP_BACKPATCH; JSOP_BACKPATCH_PUSH for jumps that push a
+ result on the interpreter's stack, namely JSOP_GOSUB; or JSOP_BACKPATCH_POP
+ for branch ops) whose nuses/ndefs counts help keep the stack balanced, but
+ whose opcode format distinguishes its backpatch delta immediate operand from
+ a normal jump offset.
+ */
+static int
+BalanceJumpTargets(JSJumpTarget **jtp)
+{
+ JSJumpTarget *jt, *jt2, *root;
+ int dir, otherDir, heightChanged;
+ JSBool doubleRotate;
+
+ jt = *jtp;
+ JS_ASSERT(jt->balance != 0);
+
+ if (jt->balance < -1) {
+ dir = JT_RIGHT;
+ doubleRotate = (jt->kids[JT_LEFT]->balance > 0);
+ } else if (jt->balance > 1) {
+ dir = JT_LEFT;
+ doubleRotate = (jt->kids[JT_RIGHT]->balance < 0);
+ } else {
+ return 0;
+ }
+
+ otherDir = JT_OTHER_DIR(dir);
+ if (doubleRotate) {
+ jt2 = jt->kids[otherDir];
+ *jtp = root = jt2->kids[dir];
+
+ jt->kids[otherDir] = root->kids[dir];
+ root->kids[dir] = jt;
+
+ jt2->kids[dir] = root->kids[otherDir];
+ root->kids[otherDir] = jt2;
+
+ heightChanged = 1;
+ root->kids[JT_LEFT]->balance = -JS_MAX(root->balance, 0);
+ root->kids[JT_RIGHT]->balance = -JS_MIN(root->balance, 0);
+ root->balance = 0;
+ } else {
+ *jtp = root = jt->kids[otherDir];
+ jt->kids[otherDir] = root->kids[dir];
+ root->kids[dir] = jt;
+
+ heightChanged = (root->balance != 0);
+ jt->balance = -((dir == JT_LEFT) ? --root->balance : ++root->balance);
+ }
+
+ return heightChanged;
+}
+
+typedef struct AddJumpTargetArgs {
+ JSContext *cx;
+ JSCodeGenerator *cg;
+ ptrdiff_t offset;
+ JSJumpTarget *node;
+} AddJumpTargetArgs;
+
+static int
+AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp)
+{
+ JSJumpTarget *jt;
+ int balanceDelta;
+
+ jt = *jtp;
+ if (!jt) {
+ JSCodeGenerator *cg = args->cg;
+
+ jt = cg->jtFreeList;
+ if (jt) {
+ cg->jtFreeList = jt->kids[JT_LEFT];
+ } else {
+ JS_ARENA_ALLOCATE_CAST(jt, JSJumpTarget *, &args->cx->tempPool,
+ sizeof *jt);
+ if (!jt) {
+ JS_ReportOutOfMemory(args->cx);
+ return 0;
+ }
+ }
+ jt->offset = args->offset;
+ jt->balance = 0;
+ jt->kids[JT_LEFT] = jt->kids[JT_RIGHT] = NULL;
+ cg->numJumpTargets++;
+ args->node = jt;
+ *jtp = jt;
+ return 1;
+ }
+
+ if (jt->offset == args->offset) {
+ args->node = jt;
+ return 0;
+ }
+
+ if (args->offset < jt->offset)
+ balanceDelta = -AddJumpTarget(args, &jt->kids[JT_LEFT]);
+ else
+ balanceDelta = AddJumpTarget(args, &jt->kids[JT_RIGHT]);
+ if (!args->node)
+ return 0;
+
+ jt->balance += balanceDelta;
+ return (balanceDelta && jt->balance)
+ ? 1 - BalanceJumpTargets(jtp)
+ : 0;
+}
+
+#ifdef DEBUG_brendan
+static int AVLCheck(JSJumpTarget *jt)
+{
+ int lh, rh;
+
+ if (!jt) return 0;
+ JS_ASSERT(-1 <= jt->balance && jt->balance <= 1);
+ lh = AVLCheck(jt->kids[JT_LEFT]);
+ rh = AVLCheck(jt->kids[JT_RIGHT]);
+ JS_ASSERT(jt->balance == rh - lh);
+ return 1 + JS_MAX(lh, rh);
+}
+#endif
+
+static JSBool
+SetSpanDepTarget(JSContext *cx, JSCodeGenerator *cg, JSSpanDep *sd,
+ ptrdiff_t off)
+{
+ AddJumpTargetArgs args;
+
+ if (off < JUMPX_OFFSET_MIN || JUMPX_OFFSET_MAX < off) {
+ ReportStatementTooLarge(cx, cg);
+ return JS_FALSE;
+ }
+
+ args.cx = cx;
+ args.cg = cg;
+ args.offset = sd->top + off;
+ args.node = NULL;
+ AddJumpTarget(&args, &cg->jumpTargets);
+ if (!args.node)
+ return JS_FALSE;
+
+#ifdef DEBUG_brendan
+ AVLCheck(cg->jumpTargets);
+#endif
+
+ SD_SET_TARGET(sd, args.node);
+ return JS_TRUE;
+}
+
+#define SPANDEPS_MIN 256
+#define SPANDEPS_SIZE(n) ((n) * sizeof(JSSpanDep))
+#define SPANDEPS_SIZE_MIN SPANDEPS_SIZE(SPANDEPS_MIN)
+
+static JSBool
+AddSpanDep(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, jsbytecode *pc2,
+ ptrdiff_t off)
+{
+ uintN index;
+ JSSpanDep *sdbase, *sd;
+ size_t size;
+
+ index = cg->numSpanDeps;
+ if (index + 1 == 0) {
+ ReportStatementTooLarge(cx, cg);
+ return JS_FALSE;
+ }
+
+ if ((index & (index - 1)) == 0 &&
+ (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) {
+ if (!sdbase) {
+ size = SPANDEPS_SIZE_MIN;
+ JS_ARENA_ALLOCATE_CAST(sdbase, JSSpanDep *, &cx->tempPool, size);
+ } else {
+ size = SPANDEPS_SIZE(index);
+ JS_ARENA_GROW_CAST(sdbase, JSSpanDep *, &cx->tempPool, size, size);
+ }
+ if (!sdbase)
+ return JS_FALSE;
+ cg->spanDeps = sdbase;
+ }
+
+ cg->numSpanDeps = index + 1;
+ sd = cg->spanDeps + index;
+ sd->top = PTRDIFF(pc, CG_BASE(cg), jsbytecode);
+ sd->offset = sd->before = PTRDIFF(pc2, CG_BASE(cg), jsbytecode);
+
+ if (js_CodeSpec[*pc].format & JOF_BACKPATCH) {
+ /* Jump offset will be backpatched if off is a non-zero "bpdelta". */
+ if (off != 0) {
+ JS_ASSERT(off >= 1 + JUMP_OFFSET_LEN);
+ if (off > BPDELTA_MAX) {
+ ReportStatementTooLarge(cx, cg);
+ return JS_FALSE;
+ }
+ }
+ SD_SET_BPDELTA(sd, off);
+ } else if (off == 0) {
+ /* Jump offset will be patched directly, without backpatch chaining. */
+ SD_SET_TARGET(sd, NULL);
+ } else {
+ /* The jump offset in off is non-zero, therefore it's already known. */
+ if (!SetSpanDepTarget(cx, cg, sd, off))
+ return JS_FALSE;
+ }
+
+ if (index > SPANDEP_INDEX_MAX)
+ index = SPANDEP_INDEX_HUGE;
+ SET_SPANDEP_INDEX(pc2, index);
+ return JS_TRUE;
+}
+
+static JSBool
+BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg)
+{
+ jsbytecode *pc, *end;
+ JSOp op;
+ const JSCodeSpec *cs;
+ ptrdiff_t len, off;
+
+ pc = CG_BASE(cg);
+ end = CG_NEXT(cg);
+ while (pc < end) {
+ op = (JSOp)*pc;
+ cs = &js_CodeSpec[op];
+ len = (ptrdiff_t)cs->length;
+
+ switch (cs->format & JOF_TYPEMASK) {
+ case JOF_JUMP:
+ off = GET_JUMP_OFFSET(pc);
+ if (!AddSpanDep(cx, cg, pc, pc, off))
+ return JS_FALSE;
+ break;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case JOF_TABLESWITCH:
+ {
+ jsbytecode *pc2;
+ jsint i, low, high;
+
+ pc2 = pc;
+ off = GET_JUMP_OFFSET(pc2);
+ if (!AddSpanDep(cx, cg, pc, pc2, off))
+ return JS_FALSE;
+ pc2 += JUMP_OFFSET_LEN;
+ low = GET_JUMP_OFFSET(pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ high = GET_JUMP_OFFSET(pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ for (i = low; i <= high; i++) {
+ off = GET_JUMP_OFFSET(pc2);
+ if (!AddSpanDep(cx, cg, pc, pc2, off))
+ return JS_FALSE;
+ pc2 += JUMP_OFFSET_LEN;
+ }
+ len = 1 + pc2 - pc;
+ break;
+ }
+
+ case JOF_LOOKUPSWITCH:
+ {
+ jsbytecode *pc2;
+ jsint npairs;
+
+ pc2 = pc;
+ off = GET_JUMP_OFFSET(pc2);
+ if (!AddSpanDep(cx, cg, pc, pc2, off))
+ return JS_FALSE;
+ pc2 += JUMP_OFFSET_LEN;
+ npairs = (jsint) GET_ATOM_INDEX(pc2);
+ pc2 += ATOM_INDEX_LEN;
+ while (npairs) {
+ pc2 += ATOM_INDEX_LEN;
+ off = GET_JUMP_OFFSET(pc2);
+ if (!AddSpanDep(cx, cg, pc, pc2, off))
+ return JS_FALSE;
+ pc2 += JUMP_OFFSET_LEN;
+ npairs--;
+ }
+ len = 1 + pc2 - pc;
+ break;
+ }
+#endif /* JS_HAS_SWITCH_STATEMENT */
+ }
+
+ pc += len;
+ }
+
+ return JS_TRUE;
+}
+
+static JSSpanDep *
+GetSpanDep(JSCodeGenerator *cg, jsbytecode *pc)
+{
+ uintN index;
+ ptrdiff_t offset;
+ int lo, hi, mid;
+ JSSpanDep *sd;
+
+ index = GET_SPANDEP_INDEX(pc);
+ if (index != SPANDEP_INDEX_HUGE)
+ return cg->spanDeps + index;
+
+ offset = PTRDIFF(pc, CG_BASE(cg), jsbytecode);
+ lo = 0;
+ hi = cg->numSpanDeps - 1;
+ while (lo <= hi) {
+ mid = (lo + hi) / 2;
+ sd = cg->spanDeps + mid;
+ if (sd->before == offset)
+ return sd;
+ if (sd->before < offset)
+ lo = mid + 1;
+ else
+ hi = mid - 1;
+ }
+
+ JS_ASSERT(0);
+ return NULL;
+}
+
+static JSBool
+SetBackPatchDelta(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
+ ptrdiff_t delta)
+{
+ JSSpanDep *sd;
+
+ JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN);
+ if (!cg->spanDeps && delta < JUMP_OFFSET_MAX) {
+ SET_JUMP_OFFSET(pc, delta);
+ return JS_TRUE;
+ }
+
+ if (delta > BPDELTA_MAX) {
+ ReportStatementTooLarge(cx, cg);
+ return JS_FALSE;
+ }
+
+ if (!cg->spanDeps && !BuildSpanDepTable(cx, cg))
+ return JS_FALSE;
+
+ sd = GetSpanDep(cg, pc);
+ JS_ASSERT(SD_GET_BPDELTA(sd) == 0);
+ SD_SET_BPDELTA(sd, delta);
+ return JS_TRUE;
+}
+
+static void
+UpdateJumpTargets(JSJumpTarget *jt, ptrdiff_t pivot, ptrdiff_t delta)
+{
+ if (jt->offset > pivot) {
+ jt->offset += delta;
+ if (jt->kids[JT_LEFT])
+ UpdateJumpTargets(jt->kids[JT_LEFT], pivot, delta);
+ }
+ if (jt->kids[JT_RIGHT])
+ UpdateJumpTargets(jt->kids[JT_RIGHT], pivot, delta);
+}
+
+static JSSpanDep *
+FindNearestSpanDep(JSCodeGenerator *cg, ptrdiff_t offset, int lo,
+ JSSpanDep *guard)
+{
+ int num, hi, mid;
+ JSSpanDep *sdbase, *sd;
+
+ num = cg->numSpanDeps;
+ JS_ASSERT(num > 0);
+ hi = num - 1;
+ sdbase = cg->spanDeps;
+ while (lo <= hi) {
+ mid = (lo + hi) / 2;
+ sd = sdbase + mid;
+ if (sd->before == offset)
+ return sd;
+ if (sd->before < offset)
+ lo = mid + 1;
+ else
+ hi = mid - 1;
+ }
+ if (lo == num)
+ return guard;
+ sd = sdbase + lo;
+ JS_ASSERT(sd->before >= offset && (lo == 0 || sd[-1].before < offset));
+ return sd;
+}
+
+static void
+FreeJumpTargets(JSCodeGenerator *cg, JSJumpTarget *jt)
+{
+ if (jt->kids[JT_LEFT])
+ FreeJumpTargets(cg, jt->kids[JT_LEFT]);
+ if (jt->kids[JT_RIGHT])
+ FreeJumpTargets(cg, jt->kids[JT_RIGHT]);
+ jt->kids[JT_LEFT] = cg->jtFreeList;
+ cg->jtFreeList = jt;
+}
+
+static JSBool
+OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
+{
+ jsbytecode *pc, *oldpc, *base, *limit, *next;
+ JSSpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard;
+ ptrdiff_t offset, growth, delta, top, pivot, span, length, target;
+ JSBool done;
+ JSOp op;
+ uint32 type;
+ size_t size, incr;
+ jssrcnote *sn, *snlimit;
+ JSSrcNoteSpec *spec;
+ uintN i, n, noteIndex;
+ JSTryNote *tn, *tnlimit;
+#ifdef DEBUG_brendan
+ int passes = 0;
+#endif
+
+ base = CG_BASE(cg);
+ sdbase = cg->spanDeps;
+ sdlimit = sdbase + cg->numSpanDeps;
+ offset = CG_OFFSET(cg);
+ growth = 0;
+
+ do {
+ done = JS_TRUE;
+ delta = 0;
+ top = pivot = -1;
+ sdtop = NULL;
+ pc = NULL;
+ op = JSOP_NOP;
+ type = 0;
+#ifdef DEBUG_brendan
+ passes++;
+#endif
+
+ for (sd = sdbase; sd < sdlimit; sd++) {
+ JS_ASSERT(JT_HAS_TAG(sd->target));
+ sd->offset += delta;
+
+ if (sd->top != top) {
+ sdtop = sd;
+ top = sd->top;
+ JS_ASSERT(top == sd->before);
+ pivot = sd->offset;
+ pc = base + top;
+ op = (JSOp) *pc;
+ type = (js_CodeSpec[op].format & JOF_TYPEMASK);
+ if (JOF_TYPE_IS_EXTENDED_JUMP(type)) {
+ /*
+ * We already extended all the jump offset operands for
+ * the opcode at sd->top. Jumps and branches have only
+ * one jump offset operand, but switches have many, all
+ * of which are adjacent in cg->spanDeps.
+ */
+ continue;
+ }
+
+ JS_ASSERT(type == JOF_JUMP ||
+ type == JOF_TABLESWITCH ||
+ type == JOF_LOOKUPSWITCH);
+ }
+
+ if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) {
+ span = SD_TARGET_OFFSET(sd) - pivot;
+ if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) {
+ ptrdiff_t deltaFromTop = 0;
+
+ done = JS_FALSE;
+
+ switch (op) {
+ case JSOP_GOTO: op = JSOP_GOTOX; break;
+ case JSOP_IFEQ: op = JSOP_IFEQX; break;
+ case JSOP_IFNE: op = JSOP_IFNEX; break;
+ case JSOP_OR: op = JSOP_ORX; break;
+ case JSOP_AND: op = JSOP_ANDX; break;
+ case JSOP_GOSUB: op = JSOP_GOSUBX; break;
+ case JSOP_CASE: op = JSOP_CASEX; break;
+ case JSOP_DEFAULT: op = JSOP_DEFAULTX; break;
+ case JSOP_TABLESWITCH: op = JSOP_TABLESWITCHX; break;
+ case JSOP_LOOKUPSWITCH: op = JSOP_LOOKUPSWITCHX; break;
+ default: JS_ASSERT(0);
+ }
+ *pc = (jsbytecode) op;
+
+ for (sd2 = sdtop; sd2 < sdlimit && sd2->top == top; sd2++) {
+ if (sd2 <= sd) {
+ /*
+ * sd2->offset already includes delta as it stood
+ * before we entered this loop, but it must also
+ * include the delta relative to top due to all the
+ * extended jump offset immediates for the opcode
+ * starting at top, which we extend in this loop.
+ *
+ * If there is only one extended jump offset, then
+ * sd2->offset won't change and this for loop will
+ * iterate once only.
+ */
+ sd2->offset += deltaFromTop;
+ deltaFromTop += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN;
+ } else {
+ /*
+ * sd2 comes after sd, and won't be revisited by
+ * the outer for loop, so we have to increase its
+ * offset by delta, not merely by deltaFromTop.
+ */
+ sd2->offset += delta;
+ }
+
+ delta += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN;
+ UpdateJumpTargets(cg->jumpTargets, sd2->offset,
+ JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN);
+ }
+ sd = sd2 - 1;
+ }
+ }
+ }
+
+ growth += delta;
+ } while (!done);
+
+ if (growth) {
+#ifdef DEBUG_brendan
+ printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n",
+ cg->filename ? cg->filename : "stdin", cg->firstLine,
+ growth / (JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN), cg->numSpanDeps,
+ passes, offset + growth, offset, growth);
+#endif
+
+ /*
+ * Ensure that we have room for the extended jumps, but don't round up
+ * to a power of two -- we're done generating code, so we cut to fit.
+ */
+ limit = CG_LIMIT(cg);
+ length = offset + growth;
+ next = base + length;
+ if (next > limit) {
+ JS_ASSERT(length > BYTECODE_CHUNK);
+ size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode));
+ incr = BYTECODE_SIZE(length) - size;
+ JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
+ if (!base) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ CG_BASE(cg) = base;
+ CG_LIMIT(cg) = next = base + length;
+ }
+ CG_NEXT(cg) = next;
+
+ /*
+ * Set up a fake span dependency record to guard the end of the code
+ * being generated. This guard record is returned as a fencepost by
+ * FindNearestSpanDep if there is no real spandep at or above a given
+ * unextended code offset.
+ */
+ guard.top = -1;
+ guard.offset = offset + growth;
+ guard.before = offset;
+ guard.target = NULL;
+ }
+
+ /*
+ * Now work backwards through the span dependencies, copying chunks of
+ * bytecode between each extended jump toward the end of the grown code
+ * space, and restoring immediate offset operands for all jump bytecodes.
+ * The first chunk of bytecodes, starting at base and ending at the first
+ * extended jump offset (NB: this chunk includes the operation bytecode
+ * just before that immediate jump offset), doesn't need to be copied.
+ */
+ JS_ASSERT(sd == sdlimit);
+ top = -1;
+ while (--sd >= sdbase) {
+ if (sd->top != top) {
+ top = sd->top;
+ op = (JSOp) base[top];
+ type = (js_CodeSpec[op].format & JOF_TYPEMASK);
+
+ for (sd2 = sd - 1; sd2 >= sdbase && sd2->top == top; sd2--)
+ continue;
+ sd2++;
+ pivot = sd2->offset;
+ JS_ASSERT(top == sd2->before);
+ }
+
+ oldpc = base + sd->before;
+ span = SD_TARGET_OFFSET(sd) - pivot;
+
+ /*
+ * If this jump didn't need to be extended, restore its span immediate
+ * offset operand now, overwriting the index of sd within cg->spanDeps
+ * that was stored temporarily after *pc when BuildSpanDepTable ran.
+ *
+ * Note that span might fit in 16 bits even for an extended jump op,
+ * if the op has multiple span operands, not all of which overflowed
+ * (e.g. JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH where some cases are in
+ * range for a short jump, but others are not).
+ */
+ if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) {
+ JS_ASSERT(JUMP_OFFSET_MIN <= span && span <= JUMP_OFFSET_MAX);
+ SET_JUMP_OFFSET(oldpc, span);
+ continue;
+ }
+
+ /*
+ * Set up parameters needed to copy the next run of bytecode starting
+ * at offset (which is a cursor into the unextended, original bytecode
+ * vector), down to sd->before (a cursor of the same scale as offset,
+ * it's the index of the original jump pc). Reuse delta to count the
+ * nominal number of bytes to copy.
+ */
+ pc = base + sd->offset;
+ delta = offset - sd->before;
+ JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN);
+
+ /*
+ * Don't bother copying the jump offset we're about to reset, but do
+ * copy the bytecode at oldpc (which comes just before its immediate
+ * jump offset operand), on the next iteration through the loop, by
+ * including it in offset's new value.
+ */
+ offset = sd->before + 1;
+ size = BYTECODE_SIZE(delta - (1 + JUMP_OFFSET_LEN));
+ if (size) {
+ memmove(pc + 1 + JUMPX_OFFSET_LEN,
+ oldpc + 1 + JUMP_OFFSET_LEN,
+ size);
+ }
+
+ SET_JUMPX_OFFSET(pc, span);
+ }
+
+ if (growth) {
+ /*
+ * Fix source note deltas. Don't hardwire the delta fixup adjustment,
+ * even though currently it must be JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN
+ * at each sd that moved. The future may bring different offset sizes
+ * for span-dependent instruction operands. However, we fix only main
+ * notes here, not prolog notes -- we know that prolog opcodes are not
+ * span-dependent, and aren't likely ever to be.
+ */
+ offset = growth = 0;
+ sd = sdbase;
+ for (sn = cg->main.notes, snlimit = sn + cg->main.noteCount;
+ sn < snlimit;
+ sn = SN_NEXT(sn)) {
+ /*
+ * Recall that the offset of a given note includes its delta, and
+ * tells the offset of the annotated bytecode from the main entry
+ * point of the script.
+ */
+ offset += SN_DELTA(sn);
+ while (sd < sdlimit && sd->before < offset) {
+ /*
+ * To compute the delta to add to sn, we need to look at the
+ * spandep after sd, whose offset - (before + growth) tells by
+ * how many bytes sd's instruction grew.
+ */
+ sd2 = sd + 1;
+ if (sd2 == sdlimit)
+ sd2 = &guard;
+ delta = sd2->offset - (sd2->before + growth);
+ if (delta > 0) {
+ JS_ASSERT(delta == JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN);
+ sn = js_AddToSrcNoteDelta(cx, cg, sn, delta);
+ if (!sn)
+ return JS_FALSE;
+ snlimit = cg->main.notes + cg->main.noteCount;
+ growth += delta;
+ }
+ sd++;
+ }
+
+ /*
+ * If sn has span-dependent offset operands, check whether each
+ * covers further span-dependencies, and increase those operands
+ * accordingly. Some source notes measure offset not from the
+ * annotated pc, but from that pc plus some small bias. NB: we
+ * assume that spec->offsetBias can't itself span span-dependent
+ * instructions!
+ */
+ spec = &js_SrcNoteSpec[SN_TYPE(sn)];
+ if (spec->isSpanDep) {
+ pivot = offset + spec->offsetBias;
+ n = spec->arity;
+ for (i = 0; i < n; i++) {
+ span = js_GetSrcNoteOffset(sn, i);
+ if (span == 0)
+ continue;
+ target = pivot + span * spec->isSpanDep;
+ sd2 = FindNearestSpanDep(cg, target,
+ (target >= pivot)
+ ? sd - sdbase
+ : 0,
+ &guard);
+
+ /*
+ * Increase target by sd2's before-vs-after offset delta,
+ * which is absolute (i.e., relative to start of script,
+ * as is target). Recompute the span by subtracting its
+ * adjusted pivot from target.
+ */
+ target += sd2->offset - sd2->before;
+ span = target - (pivot + growth);
+ span *= spec->isSpanDep;
+ noteIndex = sn - cg->main.notes;
+ if (!js_SetSrcNoteOffset(cx, cg, noteIndex, i, span))
+ return JS_FALSE;
+ sn = cg->main.notes + noteIndex;
+ snlimit = cg->main.notes + cg->main.noteCount;
+ }
+ }
+ }
+
+ /*
+ * Fix try/catch notes (O(numTryNotes * log2(numSpanDeps)), but it's
+ * not clear how we can beat that).
+ */
+ for (tn = cg->tryBase, tnlimit = cg->tryNext; tn < tnlimit; tn++) {
+ /*
+ * First, look for the nearest span dependency at/above tn->start.
+ * There may not be any such spandep, in which case the guard will
+ * be returned.
+ */
+ offset = tn->start;
+ sd = FindNearestSpanDep(cg, offset, 0, &guard);
+ delta = sd->offset - sd->before;
+ tn->start = offset + delta;
+
+ /*
+ * Next, find the nearest spandep at/above tn->start + tn->length.
+ * Use its delta minus tn->start's delta to increase tn->length.
+ */
+ length = tn->length;
+ sd2 = FindNearestSpanDep(cg, offset + length, sd - sdbase, &guard);
+ if (sd2 != sd)
+ tn->length = length + sd2->offset - sd2->before - delta;
+
+ /*
+ * Finally, adjust tn->catchStart upward only if it is non-zero,
+ * and provided there are spandeps below it that grew.
+ */
+ offset = tn->catchStart;
+ if (offset != 0) {
+ sd = FindNearestSpanDep(cg, offset, sd2 - sdbase, &guard);
+ tn->catchStart = offset + sd->offset - sd->before;
+ }
+ }
+ }
+
+#ifdef DEBUG_brendan
+ {
+ uintN bigspans = 0;
+ top = -1;
+ for (sd = sdbase; sd < sdlimit; sd++) {
+ offset = sd->offset;
+
+ /* NB: sd->top cursors into the original, unextended bytecode vector. */
+ if (sd->top != top) {
+ JS_ASSERT(top == -1 ||
+ !JOF_TYPE_IS_EXTENDED_JUMP(type) ||
+ bigspans != 0);
+ bigspans = 0;
+ top = sd->top;
+ JS_ASSERT(top == sd->before);
+ op = (JSOp) base[offset];
+ type = (js_CodeSpec[op].format & JOF_TYPEMASK);
+ JS_ASSERT(type == JOF_JUMP ||
+ type == JOF_JUMPX ||
+ type == JOF_TABLESWITCH ||
+ type == JOF_TABLESWITCHX ||
+ type == JOF_LOOKUPSWITCH ||
+ type == JOF_LOOKUPSWITCHX);
+ pivot = offset;
+ }
+
+ pc = base + offset;
+ if (JOF_TYPE_IS_EXTENDED_JUMP(type)) {
+ span = GET_JUMPX_OFFSET(pc);
+ if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) {
+ bigspans++;
+ } else {
+ JS_ASSERT(type == JOF_TABLESWITCHX ||
+ type == JOF_LOOKUPSWITCHX);
+ }
+ } else {
+ span = GET_JUMP_OFFSET(pc);
+ }
+ JS_ASSERT(SD_TARGET_OFFSET(sd) == pivot + span);
+ }
+ JS_ASSERT(!JOF_TYPE_IS_EXTENDED_JUMP(type) || bigspans != 0);
+ }
+#endif
+
+ /*
+ * Reset so we optimize at most once -- cg may be used for further code
+ * generation of successive, independent, top-level statements. No jump
+ * can span top-level statements, because JS lacks goto.
+ */
+ size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps)));
+ JS_ArenaFreeAllocation(&cx->tempPool, cg->spanDeps,
+ JS_MAX(size, SPANDEPS_SIZE_MIN));
+ cg->spanDeps = NULL;
+ FreeJumpTargets(cg, cg->jumpTargets);
+ cg->jumpTargets = NULL;
+ cg->numSpanDeps = cg->numJumpTargets = 0;
+ return JS_TRUE;
+}
+
+static JSBool
+EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off)
+{
+ ptrdiff_t jmp;
+ jsbytecode *pc;
+
+ if (off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off) {
+ if (!cg->spanDeps && !BuildSpanDepTable(cx, cg))
+ return JS_FALSE;
+ }
+
+ jmp = js_Emit3(cx, cg, op, JUMP_OFFSET_HI(off), JUMP_OFFSET_LO(off));
+ if (jmp >= 0 && cg->spanDeps) {
+ pc = CG_CODE(cg, jmp);
+ if (!AddSpanDep(cx, cg, pc, pc, off))
+ return JS_FALSE;
+ }
+ return jmp;
+}
+
+static ptrdiff_t
+GetJumpOffset(JSCodeGenerator *cg, jsbytecode *pc)
+{
+ JSSpanDep *sd;
+ JSJumpTarget *jt;
+ ptrdiff_t top;
+
+ if (!cg->spanDeps)
+ return GET_JUMP_OFFSET(pc);
+
+ sd = GetSpanDep(cg, pc);
+ jt = sd->target;
+ if (!JT_HAS_TAG(jt))
+ return JT_TO_BPDELTA(jt);
+
+ top = sd->top;
+ while (--sd >= cg->spanDeps && sd->top == top)
+ continue;
+ sd++;
+ return JT_CLR_TAG(jt)->offset - sd->offset;
+}
+
+JSBool
+js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
+ ptrdiff_t off)
+{
+ if (!cg->spanDeps) {
+ if (JUMP_OFFSET_MIN <= off && off <= JUMP_OFFSET_MAX) {
+ SET_JUMP_OFFSET(pc, off);
+ return JS_TRUE;
+ }
+
+ if (!BuildSpanDepTable(cx, cg))
+ return JS_FALSE;
+ }
+
+ return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off);
+}
+
+JSBool
+js_InWithStatement(JSTreeContext *tc)
+{
+ JSStmtInfo *stmt;
+
+ for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
+ if (stmt->type == STMT_WITH)
+ return JS_TRUE;
+ }
+ return JS_FALSE;
+}
+
+JSBool
+js_InCatchBlock(JSTreeContext *tc, JSAtom *atom)
+{
+ JSStmtInfo *stmt;
+
+ for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
+ if (stmt->type == STMT_CATCH && stmt->label == atom)
+ return JS_TRUE;
+ }
+ return JS_FALSE;
+}
+
+void
+js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
+ ptrdiff_t top)
+{
+ stmt->type = type;
+ SET_STATEMENT_TOP(stmt, top);
+ stmt->label = NULL;
+ stmt->down = tc->topStmt;
+ tc->topStmt = stmt;
+}
+
+/*
+ * Emit a backpatch op with offset pointing to the previous jump of this type,
+ * so that we can walk back up the chain fixing up the op and jump offset.
+ */
+#define EMIT_BACKPATCH_OP(cx, cg, last, op, jmp) \
+ JS_BEGIN_MACRO \
+ ptrdiff_t offset, delta; \
+ offset = CG_OFFSET(cg); \
+ delta = offset - (last); \
+ last = offset; \
+ JS_ASSERT(delta > 0); \
+ jmp = EmitJump((cx), (cg), (op), (delta)); \
+ JS_END_MACRO
+
+/* Emit additional bytecode(s) for non-local jumps. */
+static JSBool
+EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
+ JSOp *returnop)
+{
+ intN depth;
+ JSStmtInfo *stmt;
+ ptrdiff_t jmp;
+
+ /*
+ * Return from within a try block that has a finally clause must be split
+ * into two ops: JSOP_SETRVAL, to pop the r.v. and store it in fp->rval;
+ * and JSOP_RETRVAL, which makes control flow go back to the caller, who
+ * picks up fp->rval as usual. Otherwise, the stack will be unbalanced
+ * when executing the finally clause.
+ *
+ * We mutate *returnop once only if we find an enclosing try-block (viz,
+ * STMT_FINALLY) to ensure that we emit just one JSOP_SETRVAL before one
+ * or more JSOP_GOSUBs and other fixup opcodes emitted by this function.
+ * Our caller (the TOK_RETURN case of js_EmitTree) then emits *returnop.
+ * The fixup opcodes and gosubs must interleave in the proper order, from
+ * inner statement to outer, so that finally clauses run at the correct
+ * stack depth.
+ */
+ if (returnop) {
+ JS_ASSERT(*returnop == JSOP_RETURN);
+ for (stmt = cg->treeContext.topStmt; stmt != toStmt;
+ stmt = stmt->down) {
+ if (stmt->type == STMT_FINALLY) {
+ if (js_Emit1(cx, cg, JSOP_SETRVAL) < 0)
+ return JS_FALSE;
+ *returnop = JSOP_RETRVAL;
+ break;
+ }
+ }
+
+ /*
+ * If there are no try-with-finally blocks open around this return
+ * statement, we can generate a return forthwith and skip generating
+ * any fixup code.
+ */
+ if (*returnop == JSOP_RETURN)
+ return JS_TRUE;
+ }
+
+ /*
+ * The non-local jump fixup we emit will unbalance cg->stackDepth, because
+ * the fixup replicates balanced code such as JSOP_LEAVEWITH emitted at the
+ * end of a with statement, so we save cg->stackDepth here and restore it
+ * just before a successful return.
+ */
+ depth = cg->stackDepth;
+ for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) {
+ switch (stmt->type) {
+ case STMT_FINALLY:
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
+ return JS_FALSE;
+ EMIT_BACKPATCH_OP(cx, cg, stmt->gosub, JSOP_BACKPATCH_PUSH, jmp);
+ if (jmp < 0)
+ return JS_FALSE;
+ break;
+
+ case STMT_WITH:
+ case STMT_CATCH:
+ /* There's a With object on the stack that we need to pop. */
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)
+ return JS_FALSE;
+ break;
+
+ case STMT_FOR_IN_LOOP:
+ /*
+ * The iterator and the object being iterated need to be popped.
+ * JSOP_POP2 isn't decompiled, so it doesn't need to be HIDDEN.
+ */
+ if (js_Emit1(cx, cg, JSOP_POP2) < 0)
+ return JS_FALSE;
+ break;
+
+ case STMT_SUBROUTINE:
+ /* There's a retsub pc-offset on the stack that we need to pop. */
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_POP) < 0)
+ return JS_FALSE;
+ break;
+
+ default:;
+ }
+ }
+
+ cg->stackDepth = depth;
+ return JS_TRUE;
+}
+
+static ptrdiff_t
+EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
+ ptrdiff_t *last, JSAtomListElement *label, JSSrcNoteType noteType)
+{
+ intN index;
+ ptrdiff_t jmp;
+
+ if (!EmitNonLocalJumpFixup(cx, cg, toStmt, NULL))
+ return -1;
+
+ if (label) {
+ index = js_NewSrcNote(cx, cg, noteType);
+ if (index < 0)
+ return -1;
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)index, 0,
+ (ptrdiff_t) ALE_INDEX(label))) {
+ return -1;
+ }
+ } else if (noteType != SRC_NULL) {
+ if (js_NewSrcNote(cx, cg, noteType) < 0)
+ return -1;
+ }
+
+ EMIT_BACKPATCH_OP(cx, cg, *last, JSOP_BACKPATCH, jmp);
+ return jmp;
+}
+
+static JSBool
+BackPatch(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t last,
+ jsbytecode *target, jsbytecode op)
+{
+ jsbytecode *pc, *stop;
+ ptrdiff_t delta, span;
+
+ pc = CG_CODE(cg, last);
+ stop = CG_CODE(cg, -1);
+ while (pc != stop) {
+ delta = GetJumpOffset(cg, pc);
+ span = PTRDIFF(target, pc, jsbytecode);
+ CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, span);
+
+ /*
+ * Set *pc after jump offset in case bpdelta didn't overflow, but span
+ * does (if so, CHECK_AND_SET_JUMP_OFFSET might call BuildSpanDepTable
+ * and need to see the JSOP_BACKPATCH* op at *pc).
+ */
+ *pc = op;
+ pc -= delta;
+ }
+ return JS_TRUE;
+}
+
+void
+js_PopStatement(JSTreeContext *tc)
+{
+ tc->topStmt = tc->topStmt->down;
+}
+
+JSBool
+js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg)
+{
+ JSStmtInfo *stmt;
+
+ stmt = cg->treeContext.topStmt;
+ if (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) ||
+ !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update),
+ JSOP_GOTO)) {
+ return JS_FALSE;
+ }
+ js_PopStatement(&cg->treeContext);
+ return JS_TRUE;
+}
+
+/*
+ * Emit a bytecode and its 2-byte constant (atom) index immediate operand.
+ * NB: We use cx and cg from our caller's lexical environment, and return
+ * false on error.
+ */
+#define EMIT_ATOM_INDEX_OP(op, atomIndex) \
+ JS_BEGIN_MACRO \
+ if (js_Emit3(cx, cg, op, ATOM_INDEX_HI(atomIndex), \
+ ATOM_INDEX_LO(atomIndex)) < 0) { \
+ return JS_FALSE; \
+ } \
+ JS_END_MACRO
+
+static JSBool
+EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
+{
+ JSAtomListElement *ale;
+
+ ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(op, ALE_INDEX(ale));
+ return JS_TRUE;
+}
+
+/*
+ * This routine tries to optimize name gets and sets to stack slot loads and
+ * stores, given the variables object and scope chain in cx's top frame, the
+ * compile-time context in tc, and a TOK_NAME node pn. It returns false on
+ * error, true on success.
+ *
+ * The caller can inspect pn->pn_slot for a non-negative slot number to tell
+ * whether optimization occurred, in which case LookupArgOrVar also updated
+ * pn->pn_op. If pn->pn_slot is still -1 on return, pn->pn_op nevertheless
+ * may have been optimized, e.g., from JSOP_NAME to JSOP_ARGUMENTS. Whether
+ * or not pn->pn_op was modified, if this function finds an argument or local
+ * variable name, pn->pn_attrs will contain the property's attributes after a
+ * successful return.
+ */
+static JSBool
+LookupArgOrVar(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
+{
+ JSObject *obj, *pobj;
+ JSClass *clasp;
+ JSAtom *atom;
+ JSScopeProperty *sprop;
+ JSOp op;
+
+ JS_ASSERT(pn->pn_type == TOK_NAME);
+ if (pn->pn_slot >= 0 || pn->pn_op == JSOP_ARGUMENTS)
+ return JS_TRUE;
+
+ /*
+ * We can't optimize if var and closure (a local function not in a larger
+ * expression and not at top-level within another's body) collide.
+ * XXX suboptimal: keep track of colliding names and deoptimize only those
+ */
+ if (tc->flags & TCF_FUN_CLOSURE_VS_VAR)
+ return JS_TRUE;
+
+ /*
+ * We can't optimize if we're not compiling a function body, whether via
+ * eval, or directly when compiling a function statement or expression.
+ */
+ obj = cx->fp->varobj;
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if (clasp != &js_FunctionClass && clasp != &js_CallClass)
+ return JS_TRUE;
+
+ /*
+ * We can't optimize if we're in an eval called inside a with statement,
+ * or we're compiling a with statement and its body, or we're in a catch
+ * block whose exception variable has the same name as pn.
+ */
+ atom = pn->pn_atom;
+ if (cx->fp->scopeChain != obj ||
+ js_InWithStatement(tc) ||
+ js_InCatchBlock(tc, atom)) {
+ return JS_TRUE;
+ }
+
+ /*
+ * Ok, we may be able to optimize name to stack slot. Look for an argument
+ * or variable property in the function, or its call object, not found in
+ * any prototype object. Rewrite pn_op and update pn accordingly. NB: We
+ * know that JSOP_DELNAME on an argument or variable must evaluate to
+ * false, due to JSPROP_PERMANENT.
+ */
+ if (!js_LookupProperty(cx, obj, (jsid)atom, &pobj, (JSProperty **)&sprop))
+ return JS_FALSE;
+ op = pn->pn_op;
+ if (sprop) {
+ if (pobj == obj) {
+ JSPropertyOp getter = sprop->getter;
+
+ if (getter == js_GetArgument) {
+ switch (op) {
+ case JSOP_NAME: op = JSOP_GETARG; break;
+ case JSOP_SETNAME: op = JSOP_SETARG; break;
+ case JSOP_INCNAME: op = JSOP_INCARG; break;
+ case JSOP_NAMEINC: op = JSOP_ARGINC; break;
+ case JSOP_DECNAME: op = JSOP_DECARG; break;
+ case JSOP_NAMEDEC: op = JSOP_ARGDEC; break;
+ case JSOP_FORNAME: op = JSOP_FORARG; break;
+ case JSOP_DELNAME: op = JSOP_FALSE; break;
+ default: JS_ASSERT(0);
+ }
+ } else if (getter == js_GetLocalVariable ||
+ getter == js_GetCallVariable)
+ {
+ switch (op) {
+ case JSOP_NAME: op = JSOP_GETVAR; break;
+ case JSOP_SETNAME: op = JSOP_SETVAR; break;
+ case JSOP_SETCONST: op = JSOP_SETVAR; break;
+ case JSOP_INCNAME: op = JSOP_INCVAR; break;
+ case JSOP_NAMEINC: op = JSOP_VARINC; break;
+ case JSOP_DECNAME: op = JSOP_DECVAR; break;
+ case JSOP_NAMEDEC: op = JSOP_VARDEC; break;
+ case JSOP_FORNAME: op = JSOP_FORVAR; break;
+ case JSOP_DELNAME: op = JSOP_FALSE; break;
+ default: JS_ASSERT(0);
+ }
+ }
+ if (op != pn->pn_op) {
+ pn->pn_op = op;
+ pn->pn_slot = sprop->shortid;
+ }
+ pn->pn_attrs = sprop->attrs;
+ }
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ }
+
+ if (pn->pn_slot < 0) {
+ /*
+ * We couldn't optimize it, so it's not an arg or local var name. Now
+ * we must check for the predefined arguments variable. It may be
+ * overridden by assignment, in which case the function is heavyweight
+ * and the interpreter will look up 'arguments' in the function's call
+ * object.
+ */
+ if (pn->pn_op == JSOP_NAME &&
+ atom == cx->runtime->atomState.argumentsAtom) {
+ pn->pn_op = JSOP_ARGUMENTS;
+ return JS_TRUE;
+ }
+
+ tc->flags |= TCF_FUN_USES_NONLOCALS;
+ }
+ return JS_TRUE;
+}
+
+/*
+ * If pn contains a useful expression, return true with *answer set to true.
+ * If pn contains a useless expression, return true with *answer set to false.
+ * Return false on error.
+ *
+ * The caller should initialize *answer to false and invoke this function on
+ * an expression statement or similar subtree to decide whether the tree could
+ * produce code that has any side effects. For an expression statement, we
+ * define useless code as code with no side effects, because the main effect,
+ * the value left on the stack after the code executes, will be discarded by a
+ * pop bytecode.
+ */
+static JSBool
+CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
+ JSBool *answer)
+{
+ JSBool ok;
+ JSFunction *fun;
+ JSParseNode *pn2;
+
+ ok = JS_TRUE;
+ if (!pn || *answer)
+ return ok;
+
+ switch (pn->pn_arity) {
+ case PN_FUNC:
+ /*
+ * A named function is presumed useful: we can't yet know that it is
+ * not called. The side effects are the creation of a scope object
+ * to parent this function object, and the binding of the function's
+ * name in that scope object. See comments at case JSOP_NAMEDFUNOBJ:
+ * in jsinterp.c.
+ */
+ fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(pn->pn_funAtom));
+ if (fun->atom)
+ *answer = JS_TRUE;
+ break;
+
+ case PN_LIST:
+ if (pn->pn_type == TOK_NEW ||
+ pn->pn_type == TOK_LP ||
+ pn->pn_type == TOK_LB) {
+ /*
+ * All invocation operations (construct: TOK_NEW, call: TOK_LP)
+ * are presumed to be useful, because they may have side effects
+ * even if their main effect (their return value) is discarded.
+ *
+ * TOK_LB binary trees of 3 or more nodes are flattened into lists
+ * to avoid too much recursion. All such lists must be presumed
+ * to be useful because each index operation could invoke a getter
+ * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
+ * does not apply here: arguments[i][j] might invoke a getter).
+ */
+ *answer = JS_TRUE;
+ } else {
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
+ ok &= CheckSideEffects(cx, tc, pn2, answer);
+ }
+ break;
+
+ case PN_TERNARY:
+ ok = CheckSideEffects(cx, tc, pn->pn_kid1, answer) &&
+ CheckSideEffects(cx, tc, pn->pn_kid2, answer) &&
+ CheckSideEffects(cx, tc, pn->pn_kid3, answer);
+ break;
+
+ case PN_BINARY:
+ if (pn->pn_type == TOK_ASSIGN) {
+ /*
+ * Assignment is presumed to be useful, even if the next operation
+ * is another assignment overwriting this one's ostensible effect,
+ * because the left operand may be a property with a setter that
+ * has side effects.
+ */
+ *answer = JS_TRUE;
+ } else {
+ if (pn->pn_type == TOK_LB) {
+ pn2 = pn->pn_left;
+ if (pn2->pn_type == TOK_NAME && !LookupArgOrVar(cx, tc, pn2))
+ return JS_FALSE;
+ if (pn2->pn_op != JSOP_ARGUMENTS) {
+ /*
+ * Any indexed property reference could call a getter with
+ * side effects, except for arguments[i] where arguments is
+ * unambiguous.
+ */
+ *answer = JS_TRUE;
+ }
+ }
+ ok = CheckSideEffects(cx, tc, pn->pn_left, answer) &&
+ CheckSideEffects(cx, tc, pn->pn_right, answer);
+ }
+ break;
+
+ case PN_UNARY:
+ if (pn->pn_type == TOK_INC || pn->pn_type == TOK_DEC ||
+ pn->pn_type == TOK_DELETE ||
+ pn->pn_type == TOK_THROW ||
+ pn->pn_type == TOK_DEFSHARP) {
+ /* All these operations have effects that we must commit. */
+ *answer = JS_TRUE;
+ } else {
+ ok = CheckSideEffects(cx, tc, pn->pn_kid, answer);
+ }
+ break;
+
+ case PN_NAME:
+ if (pn->pn_type == TOK_NAME) {
+ if (!LookupArgOrVar(cx, tc, pn))
+ return JS_FALSE;
+ if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) {
+ /*
+ * Not an argument or local variable use, so this expression
+ * could invoke a getter that has side effects.
+ */
+ *answer = JS_TRUE;
+ }
+ }
+ pn2 = pn->pn_expr;
+ if (pn->pn_type == TOK_DOT && pn2->pn_type == TOK_NAME) {
+ if (!LookupArgOrVar(cx, tc, pn2))
+ return JS_FALSE;
+ if (!(pn2->pn_op == JSOP_ARGUMENTS &&
+ pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
+ /*
+ * Any dotted property reference could call a getter, except
+ * for arguments.length where arguments is unambiguous.
+ */
+ *answer = JS_TRUE;
+ }
+ }
+ ok = CheckSideEffects(cx, tc, pn2, answer);
+ break;
+
+ case PN_NULLARY:
+ if (pn->pn_type == TOK_DEBUGGER)
+ *answer = JS_TRUE;
+ break;
+ }
+ return ok;
+}
+
+static JSBool
+EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
+{
+ JSParseNode *pn2, *pndot, *pnup, *pndown;
+ ptrdiff_t top;
+ JSAtomListElement *ale;
+
+ pn2 = pn->pn_expr;
+ if (op == JSOP_GETPROP &&
+ pn->pn_type == TOK_DOT &&
+ pn2->pn_type == TOK_NAME) {
+ /* Try to optimize arguments.length into JSOP_ARGCNT. */
+ if (!LookupArgOrVar(cx, &cg->treeContext, pn2))
+ return JS_FALSE;
+ if (pn2->pn_op == JSOP_ARGUMENTS &&
+ pn->pn_atom == cx->runtime->atomState.lengthAtom) {
+ return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0;
+ }
+ }
+
+ /*
+ * If the object operand is also a dotted property reference, reverse the
+ * list linked via pn_expr temporarily so we can iterate over it from the
+ * bottom up (reversing again as we go), to avoid excessive recursion.
+ */
+ if (pn2->pn_type == TOK_DOT) {
+ pndot = pn2;
+ pnup = NULL;
+ top = CG_OFFSET(cg);
+ for (;;) {
+ /* Reverse pndot->pn_expr to point up, not down. */
+ pndot->pn_offset = top;
+ pndown = pndot->pn_expr;
+ pndot->pn_expr = pnup;
+ if (pndown->pn_type != TOK_DOT)
+ break;
+ pnup = pndot;
+ pndot = pndown;
+ }
+
+ /* pndown is a primary expression, not a dotted property reference. */
+ if (!js_EmitTree(cx, cg, pndown))
+ return JS_FALSE;
+
+ do {
+ /* Walk back up the list, emitting annotated name ops. */
+ if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
+ CG_OFFSET(cg) - pndown->pn_offset) < 0) {
+ return JS_FALSE;
+ }
+ ale = js_IndexAtom(cx, pndot->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(pndot->pn_op, ALE_INDEX(ale));
+
+ /* Reverse the pn_expr link again. */
+ pnup = pndot->pn_expr;
+ pndot->pn_expr = pndown;
+ pndown = pndot;
+ } while ((pndot = pnup) != NULL);
+ } else {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ }
+
+ if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - pn2->pn_offset) < 0)
+ return JS_FALSE;
+ if (!pn->pn_atom) {
+ JS_ASSERT(op == JSOP_IMPORTALL);
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ } else {
+ ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(op, ALE_INDEX(ale));
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
+{
+ ptrdiff_t top;
+ JSParseNode *left, *right, *next;
+ jsint slot;
+
+ top = CG_OFFSET(cg);
+ if (pn->pn_arity == PN_LIST) {
+ /* Left-associative operator chain to avoid too much recursion. */
+ JS_ASSERT(pn->pn_op == JSOP_GETELEM);
+ JS_ASSERT(pn->pn_count >= 3);
+ left = pn->pn_head;
+ right = PN_LAST(pn);
+ next = left->pn_next;
+ JS_ASSERT(next != right);
+
+ /*
+ * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by
+ * one or more index expression and JSOP_GETELEM op pairs.
+ */
+ if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
+ if (!LookupArgOrVar(cx, &cg->treeContext, left))
+ return JS_FALSE;
+ if (left->pn_op == JSOP_ARGUMENTS &&
+ JSDOUBLE_IS_INT(next->pn_dval, slot) &&
+ (jsuint)slot < ATOM_INDEX_LIMIT) {
+ left->pn_offset = next->pn_offset = top;
+ EMIT_ATOM_INDEX_OP(JSOP_ARGSUB, (jsatomid)slot);
+ left = next;
+ next = left->pn_next;
+ }
+ }
+
+ /*
+ * Check whether we generated JSOP_ARGSUB, just above, and have only
+ * one more index expression to emit. Given arguments[0][j], we must
+ * skip the while loop altogether, falling through to emit code for j
+ * (in the subtree referenced by right), followed by the annotated op,
+ * at the bottom of this function.
+ */
+ JS_ASSERT(next != right || pn->pn_count == 3);
+ if (left == pn->pn_head) {
+ if (!js_EmitTree(cx, cg, left))
+ return JS_FALSE;
+ }
+ while (next != right) {
+ if (!js_EmitTree(cx, cg, next))
+ return JS_FALSE;
+ if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
+ return JS_FALSE;
+ next = next->pn_next;
+ }
+ } else {
+ JS_ASSERT(pn->pn_arity == PN_BINARY);
+ left = pn->pn_left;
+ right = pn->pn_right;
+
+ /* Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. */
+ if (op == JSOP_GETELEM &&
+ left->pn_type == TOK_NAME &&
+ right->pn_type == TOK_NUMBER) {
+ if (!LookupArgOrVar(cx, &cg->treeContext, left))
+ return JS_FALSE;
+ if (left->pn_op == JSOP_ARGUMENTS &&
+ JSDOUBLE_IS_INT(right->pn_dval, slot) &&
+ (jsuint)slot < ATOM_INDEX_LIMIT) {
+ left->pn_offset = right->pn_offset = top;
+ EMIT_ATOM_INDEX_OP(JSOP_ARGSUB, (jsatomid)slot);
+ return JS_TRUE;
+ }
+ }
+
+ if (!js_EmitTree(cx, cg, left))
+ return JS_FALSE;
+ }
+ if (!js_EmitTree(cx, cg, right))
+ return JS_FALSE;
+ if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
+ return JS_FALSE;
+ return js_Emit1(cx, cg, op) >= 0;
+}
+
+static JSBool
+EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg)
+{
+ jsint ival;
+ jsatomid atomIndex;
+ JSAtom *atom;
+ JSAtomListElement *ale;
+
+ if (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) {
+ if (ival == 0)
+ return js_Emit1(cx, cg, JSOP_ZERO) >= 0;
+ if (ival == 1)
+ return js_Emit1(cx, cg, JSOP_ONE) >= 0;
+ if ((jsuint)ival < (jsuint)ATOM_INDEX_LIMIT) {
+ atomIndex = (jsatomid)ival;
+ EMIT_ATOM_INDEX_OP(JSOP_UINT16, atomIndex);
+ return JS_TRUE;
+ }
+ atom = js_AtomizeInt(cx, ival, 0);
+ } else {
+ atom = js_AtomizeDouble(cx, dval, 0);
+ }
+ if (!atom)
+ return JS_FALSE;
+ ale = js_IndexAtom(cx, atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(JSOP_NUMBER, ALE_INDEX(ale));
+ return JS_TRUE;
+}
+
+#if JS_HAS_SWITCH_STATEMENT
+static JSBool
+EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
+ JSStmtInfo *stmtInfo)
+{
+ JSOp switchop;
+ JSBool ok, hasDefault;
+ ptrdiff_t top, off, defaultOffset;
+ JSParseNode *pn2, *pn3, *pn4;
+ uint32 ncases, tablen;
+ jsdouble d;
+ jsint i, low, high;
+ JSAtom *atom;
+ JSAtomListElement *ale;
+ intN noteIndex;
+ size_t switchsize, tablesize;
+ JSParseNode **table;
+ jsbytecode *pc;
+
+ /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */
+ switchop = JSOP_TABLESWITCH;
+ ok = JS_TRUE;
+ hasDefault = JS_FALSE;
+ defaultOffset = -1;
+
+ /* Emit code for the discriminant first. */
+ if (!js_EmitTree(cx, cg, pn->pn_kid1))
+ return JS_FALSE;
+
+ /* Switch bytecodes run from here till end of final case. */
+ top = CG_OFFSET(cg);
+ js_PushStatement(&cg->treeContext, stmtInfo, STMT_SWITCH, top);
+
+ pn2 = pn->pn_kid2;
+ ncases = pn2->pn_count;
+ tablen = 0;
+
+ if (ncases == 0 ||
+ (ncases == 1 &&
+ (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) {
+ ncases = 0;
+ low = 0;
+ high = -1;
+ } else {
+#define INTMAP_LENGTH 256
+ jsbitmap intmap_space[INTMAP_LENGTH];
+ jsbitmap *intmap = NULL;
+ int32 intmap_bitlen = 0;
+
+ low = JSVAL_INT_MAX;
+ high = JSVAL_INT_MIN;
+
+ for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
+ if (pn3->pn_type == TOK_DEFAULT) {
+ hasDefault = JS_TRUE;
+ ncases--; /* one of the "cases" was the default */
+ continue;
+ }
+
+ JS_ASSERT(pn3->pn_type == TOK_CASE);
+ if (switchop == JSOP_CONDSWITCH)
+ continue;
+
+ pn4 = pn3->pn_left;
+ switch (pn4->pn_type) {
+ case TOK_NUMBER:
+ d = pn4->pn_dval;
+ if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
+ pn3->pn_val = INT_TO_JSVAL(i);
+ } else {
+ atom = js_AtomizeDouble(cx, d, 0);
+ if (!atom) {
+ ok = JS_FALSE;
+ goto release;
+ }
+ pn3->pn_val = ATOM_KEY(atom);
+ }
+ break;
+ case TOK_STRING:
+ pn3->pn_val = ATOM_KEY(pn4->pn_atom);
+ break;
+ case TOK_PRIMARY:
+ if (pn4->pn_op == JSOP_TRUE) {
+ pn3->pn_val = JSVAL_TRUE;
+ break;
+ }
+ if (pn4->pn_op == JSOP_FALSE) {
+ pn3->pn_val = JSVAL_FALSE;
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ switchop = JSOP_CONDSWITCH;
+ continue;
+ }
+
+ JS_ASSERT(JSVAL_IS_NUMBER(pn3->pn_val) ||
+ JSVAL_IS_STRING(pn3->pn_val) ||
+ JSVAL_IS_BOOLEAN(pn3->pn_val));
+
+ if (switchop != JSOP_TABLESWITCH)
+ continue;
+ if (!JSVAL_IS_INT(pn3->pn_val)) {
+ switchop = JSOP_LOOKUPSWITCH;
+ continue;
+ }
+ i = JSVAL_TO_INT(pn3->pn_val);
+ if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) {
+ switchop = JSOP_LOOKUPSWITCH;
+ continue;
+ }
+ if (i < low)
+ low = i;
+ if (high < i)
+ high = i;
+
+ /*
+ * Check for duplicates, which require a JSOP_LOOKUPSWITCH.
+ * We bias i by 65536 if it's negative, and hope that's a rare
+ * case (because it requires a malloc'd bitmap).
+ */
+ if (i < 0)
+ i += JS_BIT(16);
+ if (i >= intmap_bitlen) {
+ if (!intmap &&
+ i < (INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2)) {
+ intmap = intmap_space;
+ intmap_bitlen = INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2;
+ } else {
+ /* Just grab 8K for the worst-case bitmap. */
+ intmap_bitlen = JS_BIT(16);
+ intmap = (jsbitmap *)
+ JS_malloc(cx,
+ (JS_BIT(16) >> JS_BITS_PER_WORD_LOG2)
+ * sizeof(jsbitmap));
+ if (!intmap) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ }
+ memset(intmap, 0, intmap_bitlen >> JS_BITS_PER_BYTE_LOG2);
+ }
+ if (JS_TEST_BIT(intmap, i)) {
+ switchop = JSOP_LOOKUPSWITCH;
+ continue;
+ }
+ JS_SET_BIT(intmap, i);
+ }
+
+ release:
+ if (intmap && intmap != intmap_space)
+ JS_free(cx, intmap);
+ if (!ok)
+ return JS_FALSE;
+
+ /*
+ * Compute table length and select lookup instead if overlarge or
+ * more than half-sparse.
+ */
+ if (switchop == JSOP_TABLESWITCH) {
+ tablen = (uint32)(high - low + 1);
+ if (tablen >= JS_BIT(16) || tablen > 2 * ncases)
+ switchop = JSOP_LOOKUPSWITCH;
+ }
+ }
+
+ /*
+ * Emit a note with two offsets: first tells total switch code length,
+ * second tells offset to first JSOP_CASE if condswitch.
+ */
+ noteIndex = js_NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0);
+ if (noteIndex < 0)
+ return JS_FALSE;
+
+ if (switchop == JSOP_CONDSWITCH) {
+ /*
+ * 0 bytes of immediate for unoptimized ECMAv2 switch.
+ */
+ switchsize = 0;
+ } else if (switchop == JSOP_TABLESWITCH) {
+ /*
+ * 3 offsets (len, low, high) before the table, 1 per entry.
+ */
+ switchsize = (size_t)(JUMP_OFFSET_LEN * (3 + tablen));
+ } else {
+ /*
+ * JSOP_LOOKUPSWITCH:
+ * 1 offset (len) and 1 atom index (npairs) before the table,
+ * 1 atom index and 1 jump offset per entry.
+ */
+ switchsize = (size_t)(JUMP_OFFSET_LEN + ATOM_INDEX_LEN +
+ (ATOM_INDEX_LEN + JUMP_OFFSET_LEN) * ncases);
+ }
+
+ /*
+ * Emit switchop followed by switchsize bytes of jump or lookup table.
+ *
+ * If switchop is JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH, it is crucial
+ * to emit the immediate operand(s) by which bytecode readers such as
+ * BuildSpanDepTable discover the length of the switch opcode *before*
+ * calling js_SetJumpOffset (which may call BuildSpanDepTable). It's
+ * also important to zero all unknown jump offset immediate operands,
+ * so they can be converted to span dependencies with null targets to
+ * be computed later (js_EmitN zeros switchsize bytes after switchop).
+ */
+ if (js_EmitN(cx, cg, switchop, switchsize) < 0)
+ return JS_FALSE;
+
+ off = -1;
+ if (switchop == JSOP_CONDSWITCH) {
+ intN caseNoteIndex = -1;
+
+ /* Emit code for evaluating cases and jumping to case statements. */
+ for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
+ pn4 = pn3->pn_left;
+ if (pn4 && !js_EmitTree(cx, cg, pn4))
+ return JS_FALSE;
+ if (caseNoteIndex >= 0) {
+ /* off is the previous JSOP_CASE's bytecode offset. */
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0,
+ CG_OFFSET(cg) - off)) {
+ return JS_FALSE;
+ }
+ }
+ if (pn3->pn_type == TOK_DEFAULT)
+ continue;
+ caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
+ if (caseNoteIndex < 0)
+ return JS_FALSE;
+ off = EmitJump(cx, cg, JSOP_CASE, 0);
+ if (off < 0)
+ return JS_FALSE;
+ pn3->pn_offset = off;
+ if (pn3 == pn2->pn_head) {
+ /* Switch note's second offset is to first JSOP_CASE. */
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
+ off - top)) {
+ return JS_FALSE;
+ }
+ }
+ }
+
+ /* Emit default even if no explicit default statement. */
+ defaultOffset = EmitJump(cx, cg, JSOP_DEFAULT, 0);
+ if (defaultOffset < 0)
+ return JS_FALSE;
+ } else if (switchop == JSOP_TABLESWITCH) {
+ /* Fill in switch bounds, which we know fit in 16-bit offsets. */
+ pc = CG_CODE(cg, top + JUMP_OFFSET_LEN);
+ SET_JUMP_OFFSET(pc, low);
+ pc += JUMP_OFFSET_LEN;
+ SET_JUMP_OFFSET(pc, high);
+ pc += JUMP_OFFSET_LEN;
+ } else {
+ JS_ASSERT(switchop == JSOP_LOOKUPSWITCH);
+
+ /* Fill in the number of cases. */
+ pc = CG_CODE(cg, top + JUMP_OFFSET_LEN);
+ SET_ATOM_INDEX(pc, ncases);
+ }
+
+ /* Emit code for each case's statements, copying pn_offset up to pn3. */
+ for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
+ if (switchop == JSOP_CONDSWITCH && pn3->pn_type != TOK_DEFAULT)
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, pn3->pn_offset);
+ pn4 = pn3->pn_right;
+ if (!js_EmitTree(cx, cg, pn4))
+ return JS_FALSE;
+ pn3->pn_offset = pn4->pn_offset;
+ if (pn3->pn_type == TOK_DEFAULT)
+ off = pn3->pn_offset - top;
+ }
+
+ if (!hasDefault) {
+ /* If no default case, offset for default is to end of switch. */
+ off = CG_OFFSET(cg) - top;
+ }
+
+ /* We better have set "off" by now. */
+ JS_ASSERT(off != -1);
+
+ /* Set the default offset (to end of switch if no default). */
+ pc = NULL;
+ if (switchop == JSOP_CONDSWITCH) {
+ JS_ASSERT(defaultOffset != -1);
+ if (!js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset),
+ off - (defaultOffset - top))) {
+ return JS_FALSE;
+ }
+ } else {
+ pc = CG_CODE(cg, top);
+ if (!js_SetJumpOffset(cx, cg, pc, off))
+ return JS_FALSE;
+ pc += JUMP_OFFSET_LEN;
+ }
+
+ /* Set the SRC_SWITCH note's offset operand to tell end of switch. */
+ off = CG_OFFSET(cg) - top;
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off))
+ return JS_FALSE;
+
+ if (switchop == JSOP_TABLESWITCH) {
+ /* Skip over the already-initialized switch bounds. */
+ pc += 2 * JUMP_OFFSET_LEN;
+
+ /* Fill in the jump table, if there is one. */
+ if (tablen) {
+ /* Avoid bloat for a compilation unit with many switches. */
+ tablesize = (size_t)tablen * sizeof *table;
+ table = (JSParseNode **) JS_malloc(cx, tablesize);
+ if (!table)
+ return JS_FALSE;
+ memset(table, 0, tablesize);
+ for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
+ if (pn3->pn_type == TOK_DEFAULT)
+ continue;
+ i = JSVAL_TO_INT(pn3->pn_val);
+ i -= low;
+ JS_ASSERT((uint32)i < tablen);
+ table[i] = pn3;
+ }
+ for (i = 0; i < (jsint)tablen; i++) {
+ pn3 = table[i];
+ off = pn3 ? pn3->pn_offset - top : 0;
+ ok = js_SetJumpOffset(cx, cg, pc, off);
+ if (!ok)
+ break;
+ pc += JUMP_OFFSET_LEN;
+ }
+ JS_free(cx, table);
+ if (!ok)
+ return JS_FALSE;
+ }
+ } else if (switchop == JSOP_LOOKUPSWITCH) {
+ /* Skip over the already-initialized number of cases. */
+ pc += ATOM_INDEX_LEN;
+
+ for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
+ if (pn3->pn_type == TOK_DEFAULT)
+ continue;
+ atom = js_AtomizeValue(cx, pn3->pn_val, 0);
+ if (!atom)
+ return JS_FALSE;
+ ale = js_IndexAtom(cx, atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ SET_ATOM_INDEX(pc, ALE_INDEX(ale));
+ pc += ATOM_INDEX_LEN;
+
+ off = pn3->pn_offset - top;
+ if (!js_SetJumpOffset(cx, cg, pc, off))
+ return JS_FALSE;
+ pc += JUMP_OFFSET_LEN;
+ }
+ }
+
+ return js_PopStatementCG(cx, cg);
+}
+#endif /* JS_HAS_SWITCH_STATEMENT */
+
+JSBool
+js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
+ JSFunction *fun)
+{
+ JSStackFrame *fp, frame;
+ JSObject *funobj;
+ JSBool ok;
+
+ if (!js_AllocTryNotes(cx, cg))
+ return JS_FALSE;
+
+ fp = cx->fp;
+ funobj = fun->object;
+ if (!fp || fp->fun != fun || fp->varobj != funobj ||
+ fp->scopeChain != funobj) {
+ memset(&frame, 0, sizeof frame);
+ frame.fun = fun;
+ frame.varobj = frame.scopeChain = funobj;
+ frame.down = fp;
+ cx->fp = &frame;
+ }
+ ok = js_EmitTree(cx, cg, body);
+ cx->fp = fp;
+ if (!ok)
+ return JS_FALSE;
+
+ fun->script = js_NewScriptFromCG(cx, cg, fun);
+ if (!fun->script)
+ return JS_FALSE;
+ if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)
+ fun->flags |= JSFUN_HEAVYWEIGHT;
+ return JS_TRUE;
+}
+
+/* A macro for inlining at the top of js_EmitTree (whence it came). */
+#define UPDATE_LINE_NUMBER_NOTES(cx, cg, pn) \
+ JS_BEGIN_MACRO \
+ uintN line_ = (pn)->pn_pos.begin.lineno; \
+ uintN delta_ = line_ - CG_CURRENT_LINE(cg); \
+ if (delta_ != 0) { \
+ /* \
+ * Encode any change in the current source line number by using \
+ * either several SRC_NEWLINE notes or just one SRC_SETLINE note, \
+ * whichever consumes less space. \
+ * \
+ * NB: We handle backward line number deltas (possible with for \
+ * loops where the update part is emitted after the body, but its \
+ * line number is <= any line number in the body) here by letting \
+ * unsigned delta_ wrap to a very large number, which triggers a \
+ * SRC_SETLINE. \
+ */ \
+ CG_CURRENT_LINE(cg) = line_; \
+ if (delta_ >= (uintN)(2 + ((line_ > SN_3BYTE_OFFSET_MASK)<<1))) { \
+ if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)line_) < 0)\
+ return JS_FALSE; \
+ } else { \
+ do { \
+ if (js_NewSrcNote(cx, cg, SRC_NEWLINE) < 0) \
+ return JS_FALSE; \
+ } while (--delta_ != 0); \
+ } \
+ } \
+ JS_END_MACRO
+
+/* A function, so that we avoid macro-bloating all the other callsites. */
+static JSBool
+UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
+{
+ UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);
+ return JS_TRUE;
+}
+
+JSBool
+js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
+{
+ JSBool ok, useful, wantval;
+ JSStmtInfo *stmt, stmtInfo;
+ ptrdiff_t top, off, tmp, beq, jmp;
+ JSParseNode *pn2, *pn3;
+ JSAtom *atom;
+ JSAtomListElement *ale;
+ jsatomid atomIndex;
+ intN noteIndex;
+ JSSrcNoteType noteType;
+ jsbytecode *pc;
+ JSOp op;
+ uint32 argc;
+ int stackDummy;
+
+ if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
+ return JS_FALSE;
+ }
+
+ ok = JS_TRUE;
+ cg->emitLevel++;
+ pn->pn_offset = top = CG_OFFSET(cg);
+
+ /* Emit notes to tell the current bytecode's source line number. */
+ UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);
+
+ switch (pn->pn_type) {
+ case TOK_FUNCTION:
+ {
+ void *cg2mark;
+ JSCodeGenerator *cg2;
+ JSFunction *fun;
+
+ /* Generate code for the function's body. */
+ cg2mark = JS_ARENA_MARK(&cx->tempPool);
+ JS_ARENA_ALLOCATE_TYPE(cg2, JSCodeGenerator, &cx->tempPool);
+ if (!cg2) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ if (!js_InitCodeGenerator(cx, cg2, cg->codePool, cg->notePool,
+ cg->filename, pn->pn_pos.begin.lineno,
+ cg->principals)) {
+ return JS_FALSE;
+ }
+ cg2->treeContext.flags = pn->pn_flags | TCF_IN_FUNCTION;
+ cg2->treeContext.tryCount = pn->pn_tryCount;
+ fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(pn->pn_funAtom));
+ if (!js_EmitFunctionBody(cx, cg2, pn->pn_body, fun))
+ return JS_FALSE;
+
+ /*
+ * We need an activation object if an inner peeks out, or if such
+ * inner-peeking caused one of our inners to become heavyweight.
+ */
+ if (cg2->treeContext.flags &
+ (TCF_FUN_USES_NONLOCALS | TCF_FUN_HEAVYWEIGHT)) {
+ cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;
+ }
+ js_FinishCodeGenerator(cx, cg2);
+ JS_ARENA_RELEASE(&cx->tempPool, cg2mark);
+
+ /* Make the function object a literal in the outer script's pool. */
+ ale = js_IndexAtom(cx, pn->pn_funAtom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ atomIndex = ALE_INDEX(ale);
+
+#if JS_HAS_LEXICAL_CLOSURE
+ /* Emit a bytecode pointing to the closure object in its immediate. */
+ if (pn->pn_op != JSOP_NOP) {
+ EMIT_ATOM_INDEX_OP(pn->pn_op, atomIndex);
+ break;
+ }
+#endif
+
+ /* Top-level named functions need a nop for decompilation. */
+ noteIndex = js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)atomIndex);
+ if (noteIndex < 0 ||
+ js_Emit1(cx, cg, JSOP_NOP) < 0) {
+ return JS_FALSE;
+ }
+
+ /*
+ * Top-levels also need a prolog op to predefine their names in the
+ * variable object, or if local, to fill their stack slots.
+ */
+ CG_SWITCH_TO_PROLOG(cg);
+
+#if JS_HAS_LEXICAL_CLOSURE
+ if (cg->treeContext.flags & TCF_IN_FUNCTION) {
+ JSObject *obj, *pobj;
+ JSScopeProperty *sprop;
+ uintN slot;
+
+ obj = OBJ_GET_PARENT(cx, fun->object);
+ if (!js_LookupProperty(cx, obj, (jsid)fun->atom, &pobj,
+ (JSProperty **)&sprop)) {
+ return JS_FALSE;
+ }
+ JS_ASSERT(sprop && pobj == obj);
+ slot = sprop->shortid;
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+
+ /* Emit [JSOP_DEFLOCALFUN, local variable slot, atomIndex]. */
+ off = js_EmitN(cx, cg, JSOP_DEFLOCALFUN, VARNO_LEN+ATOM_INDEX_LEN);
+ if (off < 0)
+ return JS_FALSE;
+ pc = CG_CODE(cg, off);
+ SET_VARNO(pc, slot);
+ pc += VARNO_LEN;
+ SET_ATOM_INDEX(pc, atomIndex);
+ } else
+#endif
+ EMIT_ATOM_INDEX_OP(JSOP_DEFFUN, atomIndex);
+
+ CG_SWITCH_TO_MAIN(cg);
+ break;
+ }
+
+#if JS_HAS_EXPORT_IMPORT
+ case TOK_EXPORT:
+ pn2 = pn->pn_head;
+ if (pn2->pn_type == TOK_STAR) {
+ /*
+ * 'export *' must have no other elements in the list (what would
+ * be the point?).
+ */
+ if (js_Emit1(cx, cg, JSOP_EXPORTALL) < 0)
+ return JS_FALSE;
+ } else {
+ /*
+ * If not 'export *', the list consists of NAME nodes identifying
+ * properties of the variables object to flag as exported.
+ */
+ do {
+ ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(JSOP_EXPORTNAME, ALE_INDEX(ale));
+ } while ((pn2 = pn2->pn_next) != NULL);
+ }
+ break;
+
+ case TOK_IMPORT:
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
+ /*
+ * Each subtree on an import list is rooted by a DOT or LB node.
+ * A DOT may have a null pn_atom member, in which case pn_op must
+ * be JSOP_IMPORTALL -- see EmitPropOp above.
+ */
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ }
+ break;
+#endif /* JS_HAS_EXPORT_IMPORT */
+
+ case TOK_IF:
+ /* Initialize so we can detect else-if chains and avoid recursion. */
+ stmtInfo.type = STMT_IF;
+ beq = jmp = -1;
+ noteIndex = -1;
+
+ if_again:
+ /* Emit code for the condition before pushing stmtInfo. */
+ if (!js_EmitTree(cx, cg, pn->pn_kid1))
+ return JS_FALSE;
+ if (stmtInfo.type == STMT_IF) {
+ js_PushStatement(&cg->treeContext, &stmtInfo, STMT_IF,
+ CG_OFFSET(cg));
+ } else {
+ /*
+ * We came here from the goto further below that detects else-if
+ * chains, so we must mutate stmtInfo back into a STMT_IF record.
+ * Also (see below for why) we need a note offset for SRC_IF_ELSE
+ * to help the decompiler.
+ */
+ JS_ASSERT(stmtInfo.type == STMT_ELSE);
+ stmtInfo.type = STMT_IF;
+ if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
+ return JS_FALSE;
+ }
+
+ /* Emit an annotated branch-if-false around the then part. */
+ pn3 = pn->pn_kid3;
+ noteIndex = js_NewSrcNote(cx, cg, pn3 ? SRC_IF_ELSE : SRC_IF);
+ if (noteIndex < 0)
+ return JS_FALSE;
+ beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
+ if (beq < 0)
+ return JS_FALSE;
+
+ /* Emit code for the then and optional else parts. */
+ if (!js_EmitTree(cx, cg, pn->pn_kid2))
+ return JS_FALSE;
+ if (pn3) {
+ /* Modify stmtInfo so we know we're in the else part. */
+ stmtInfo.type = STMT_ELSE;
+
+ /*
+ * Emit a JSOP_BACKPATCH op to jump from the end of our then part
+ * around the else part. The js_PopStatementCG call at the bottom
+ * of this switch case will fix up the backpatch chain linked from
+ * stmtInfo.breaks.
+ */
+ jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks, NULL, SRC_NULL);
+ if (jmp < 0)
+ return JS_FALSE;
+
+ /* Ensure the branch-if-false comes here, then emit the else. */
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
+ if (pn3->pn_type == TOK_IF) {
+ pn = pn3;
+ goto if_again;
+ }
+
+ if (!js_EmitTree(cx, cg, pn3))
+ return JS_FALSE;
+
+ /*
+ * Annotate SRC_IF_ELSE with the offset from branch to jump, for
+ * the decompiler's benefit. We can't just "back up" from the pc
+ * of the else clause, because we don't know whether an extended
+ * jump was required to leap from the end of the then clause over
+ * the else clause.
+ */
+ if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
+ return JS_FALSE;
+ } else {
+ /* No else part, fixup the branch-if-false to come here. */
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
+ }
+ ok = js_PopStatementCG(cx, cg);
+ break;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case TOK_SWITCH:
+ /* Out of line to avoid bloating js_EmitTree's stack frame size. */
+ ok = EmitSwitch(cx, cg, pn, &stmtInfo);
+ break;
+#endif /* JS_HAS_SWITCH_STATEMENT */
+
+ case TOK_WHILE:
+ js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WHILE_LOOP, top);
+ if (!js_EmitTree(cx, cg, pn->pn_left))
+ return JS_FALSE;
+ noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
+ if (noteIndex < 0)
+ return JS_FALSE;
+ beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
+ if (beq < 0)
+ return JS_FALSE;
+ if (!js_EmitTree(cx, cg, pn->pn_right))
+ return JS_FALSE;
+ jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));
+ if (jmp < 0)
+ return JS_FALSE;
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
+ if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
+ return JS_FALSE;
+ ok = js_PopStatementCG(cx, cg);
+ break;
+
+#if JS_HAS_DO_WHILE_LOOP
+ case TOK_DO:
+ /* Emit an annotated nop so we know to decompile a 'do' keyword. */
+ if (js_NewSrcNote(cx, cg, SRC_WHILE) < 0 ||
+ js_Emit1(cx, cg, JSOP_NOP) < 0) {
+ return JS_FALSE;
+ }
+
+ /* Compile the loop body. */
+ top = CG_OFFSET(cg);
+ js_PushStatement(&cg->treeContext, &stmtInfo, STMT_DO_LOOP, top);
+ if (!js_EmitTree(cx, cg, pn->pn_left))
+ return JS_FALSE;
+
+ /* Set loop and enclosing label update offsets, for continue. */
+ stmt = &stmtInfo;
+ do {
+ stmt->update = CG_OFFSET(cg);
+ } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
+
+ /* Compile the loop condition, now that continues know where to go. */
+ if (!js_EmitTree(cx, cg, pn->pn_right))
+ return JS_FALSE;
+
+ /*
+ * No source note needed, because JSOP_IFNE is used only for do-while.
+ * If we ever use JSOP_IFNE for other purposes, we can still avoid yet
+ * another note here, by storing (jmp - top) in the SRC_WHILE note's
+ * offset, and fetching that delta in order to decompile recursively.
+ */
+ if (EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)) < 0)
+ return JS_FALSE;
+ ok = js_PopStatementCG(cx, cg);
+ break;
+#endif /* JS_HAS_DO_WHILE_LOOP */
+
+ case TOK_FOR:
+ beq = 0; /* suppress gcc warnings */
+ pn2 = pn->pn_left;
+ js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FOR_LOOP, top);
+
+ if (pn2->pn_type == TOK_IN) {
+ /* Set stmtInfo type for later testing. */
+ stmtInfo.type = STMT_FOR_IN_LOOP;
+ noteIndex = -1;
+
+ /* If the left part is var x = i, bind x, evaluate i, and pop. */
+ pn3 = pn2->pn_left;
+ if (pn3->pn_type == TOK_VAR && pn3->pn_head->pn_expr) {
+ if (!js_EmitTree(cx, cg, pn3))
+ return JS_FALSE;
+ /* Set pn3 to the variable name, to avoid another var note. */
+ pn3 = pn3->pn_head;
+ JS_ASSERT(pn3->pn_type == TOK_NAME);
+ }
+
+ /* Emit a push to allocate the iterator. */
+ if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
+ return JS_FALSE;
+
+ /* Compile the object expression to the right of 'in'. */
+ if (!js_EmitTree(cx, cg, pn2->pn_right))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_TOOBJECT) < 0)
+ return JS_FALSE;
+
+ top = CG_OFFSET(cg);
+ SET_STATEMENT_TOP(&stmtInfo, top);
+
+ /* Compile a JSOP_FOR* bytecode based on the left hand side. */
+ switch (pn3->pn_type) {
+ case TOK_VAR:
+ pn3 = pn3->pn_head;
+ if (js_NewSrcNote(cx, cg, SRC_VAR) < 0)
+ return JS_FALSE;
+ /* FALL THROUGH */
+ case TOK_NAME:
+ pn3->pn_op = JSOP_FORNAME;
+ if (!LookupArgOrVar(cx, &cg->treeContext, pn3))
+ return JS_FALSE;
+ op = pn3->pn_op;
+ if (pn3->pn_slot >= 0) {
+ if (pn3->pn_attrs & JSPROP_READONLY)
+ op = JSOP_GETVAR;
+ atomIndex = (jsatomid) pn3->pn_slot;
+ EMIT_ATOM_INDEX_OP(op, atomIndex);
+ } else {
+ if (!EmitAtomOp(cx, pn3, op, cg))
+ return JS_FALSE;
+ }
+ break;
+
+ case TOK_DOT:
+ if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg))
+ return JS_FALSE;
+ break;
+
+ case TOK_LB:
+ /*
+ * We separate the first/next bytecode from the enumerator
+ * variable binding to avoid any side-effects in the index
+ * expression (e.g., for (x[i++] in {}) should not bind x[i]
+ * or increment i at all).
+ */
+ if (!js_Emit1(cx, cg, JSOP_FORELEM))
+ return JS_FALSE;
+
+ /*
+ * Emit a SRC_WHILE note with offset telling the distance to
+ * the loop-closing jump (we can't reckon from the branch at
+ * the top of the loop, because the loop-closing jump might
+ * need to be an extended jump, independent of whether the
+ * branch is short or long).
+ */
+ noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
+ if (noteIndex < 0)
+ return JS_FALSE;
+ beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
+ if (beq < 0)
+ return JS_FALSE;
+
+ /* Now that we're safely past the IFEQ, commit side effects. */
+ if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))
+ return JS_FALSE;
+ break;
+
+ default:
+ JS_ASSERT(0);
+ }
+ if (pn3->pn_type != TOK_LB) {
+ /* Annotate so the decompiler can find the loop-closing jump. */
+ noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
+ if (noteIndex < 0)
+ return JS_FALSE;
+
+ /* Pop and test the loop condition generated by JSOP_FOR*. */
+ beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
+ if (beq < 0)
+ return JS_FALSE;
+ }
+ } else {
+ if (!pn2->pn_kid1) {
+ /* No initializer: emit an annotated nop for the decompiler. */
+ op = JSOP_NOP;
+ } else {
+ if (!js_EmitTree(cx, cg, pn2->pn_kid1))
+ return JS_FALSE;
+ op = JSOP_POP;
+ }
+ noteIndex = js_NewSrcNote(cx, cg, SRC_FOR);
+ if (noteIndex < 0 ||
+ js_Emit1(cx, cg, op) < 0) {
+ return JS_FALSE;
+ }
+
+ top = CG_OFFSET(cg);
+ SET_STATEMENT_TOP(&stmtInfo, top);
+ if (!pn2->pn_kid2) {
+ /* No loop condition: flag this fact in the source notes. */
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, 0))
+ return JS_FALSE;
+ } else {
+ if (!js_EmitTree(cx, cg, pn2->pn_kid2))
+ return JS_FALSE;
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
+ CG_OFFSET(cg) - top)) {
+ return JS_FALSE;
+ }
+ beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
+ if (beq < 0)
+ return JS_FALSE;
+ }
+
+ /* Set pn3 (used below) here to avoid spurious gcc warnings. */
+ pn3 = pn2->pn_kid3;
+ }
+
+ /* Emit code for the loop body. */
+ if (!js_EmitTree(cx, cg, pn->pn_right))
+ return JS_FALSE;
+
+ if (pn2->pn_type != TOK_IN) {
+ /* Set the second note offset so we can find the update part. */
+ JS_ASSERT(noteIndex != -1);
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
+ CG_OFFSET(cg) - top)) {
+ return JS_FALSE;
+ }
+
+ if (pn3) {
+ /* Set loop and enclosing "update" offsets, for continue. */
+ stmt = &stmtInfo;
+ do {
+ stmt->update = CG_OFFSET(cg);
+ } while ((stmt = stmt->down) != NULL &&
+ stmt->type == STMT_LABEL);
+
+ if (!js_EmitTree(cx, cg, pn3))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_POP) < 0)
+ return JS_FALSE;
+
+ /* Restore the absolute line number for source note readers. */
+ off = (ptrdiff_t) pn->pn_pos.end.lineno;
+ if (CG_CURRENT_LINE(cg) != (uintN) off) {
+ if (js_NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0)
+ return JS_FALSE;
+ CG_CURRENT_LINE(cg) = (uintN) off;
+ }
+ }
+
+ /* The third note offset helps us find the loop-closing jump. */
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,
+ CG_OFFSET(cg) - top)) {
+ return JS_FALSE;
+ }
+ }
+
+ /* Emit the loop-closing jump and fixup all jump offsets. */
+ jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));
+ if (jmp < 0)
+ return JS_FALSE;
+ if (beq > 0)
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
+ if (pn2->pn_type == TOK_IN) {
+ /* Set the SRC_WHILE note offset so we can find the closing jump. */
+ JS_ASSERT(noteIndex != -1);
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, jmp - beq))
+ return JS_FALSE;
+ }
+
+ /* Now fixup all breaks and continues (before for/in's final POP2). */
+ if (!js_PopStatementCG(cx, cg))
+ return JS_FALSE;
+
+ if (pn2->pn_type == TOK_IN) {
+ /*
+ * Generate the object and iterator pop opcodes after popping the
+ * stmtInfo stack, so breaks will go to this pop bytecode.
+ */
+ if (pn3->pn_type != TOK_LB) {
+ if (js_Emit1(cx, cg, JSOP_POP2) < 0)
+ return JS_FALSE;
+ } else {
+ /*
+ * With 'for(x[i]...)', there's only the object on the stack,
+ * so we need to hide the pop.
+ */
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_POP) < 0)
+ return JS_FALSE;
+ }
+ }
+ break;
+
+ case TOK_BREAK:
+ stmt = cg->treeContext.topStmt;
+ atom = pn->pn_atom;
+ if (atom) {
+ ale = js_IndexAtom(cx, atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ while (stmt->type != STMT_LABEL || stmt->label != atom)
+ stmt = stmt->down;
+ noteType = SRC_BREAK2LABEL;
+ } else {
+ ale = NULL;
+ while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH)
+ stmt = stmt->down;
+ noteType = SRC_NULL;
+ }
+
+ if (EmitGoto(cx, cg, stmt, &stmt->breaks, ale, noteType) < 0)
+ return JS_FALSE;
+ break;
+
+ case TOK_CONTINUE:
+ stmt = cg->treeContext.topStmt;
+ atom = pn->pn_atom;
+ if (atom) {
+ /* Find the loop statement enclosed by the matching label. */
+ JSStmtInfo *loop = NULL;
+ ale = js_IndexAtom(cx, atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ while (stmt->type != STMT_LABEL || stmt->label != atom) {
+ if (STMT_IS_LOOP(stmt))
+ loop = stmt;
+ stmt = stmt->down;
+ }
+ stmt = loop;
+ noteType = SRC_CONT2LABEL;
+ } else {
+ ale = NULL;
+ while (!STMT_IS_LOOP(stmt))
+ stmt = stmt->down;
+ noteType = SRC_CONTINUE;
+ }
+
+ if (EmitGoto(cx, cg, stmt, &stmt->continues, ale, noteType) < 0)
+ return JS_FALSE;
+ break;
+
+ case TOK_WITH:
+ if (!js_EmitTree(cx, cg, pn->pn_left))
+ return JS_FALSE;
+ js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WITH, CG_OFFSET(cg));
+ if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0)
+ return JS_FALSE;
+ if (!js_EmitTree(cx, cg, pn->pn_right))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)
+ return JS_FALSE;
+ ok = js_PopStatementCG(cx, cg);
+ break;
+
+#if JS_HAS_EXCEPTIONS
+
+ case TOK_TRY:
+ {
+ ptrdiff_t start, end, catchStart, finallyCatch, catchJump;
+ JSParseNode *iter;
+ intN depth;
+
+ /* Quell GCC overwarnings. */
+ end = catchStart = finallyCatch = catchJump = -1;
+
+/* Emit JSOP_GOTO that points to the first op after the catch/finally blocks */
+#define EMIT_CATCH_GOTO(cx, cg, jmp) \
+ EMIT_BACKPATCH_OP(cx, cg, stmtInfo.catchJump, JSOP_BACKPATCH, jmp)
+
+/* Emit JSOP_GOSUB that points to the finally block. */
+#define EMIT_FINALLY_GOSUB(cx, cg, jmp) \
+ EMIT_BACKPATCH_OP(cx, cg, stmtInfo.gosub, JSOP_BACKPATCH_PUSH, jmp)
+
+ /*
+ * Push stmtInfo to track jumps-over-catches and gosubs-to-finally
+ * for later fixup.
+ *
+ * When a finally block is `active' (STMT_FINALLY on the treeContext),
+ * non-local jumps (including jumps-over-catches) result in a GOSUB
+ * being written into the bytecode stream and fixed-up later (c.f.
+ * EMIT_BACKPATCH_OP and BackPatch).
+ */
+ js_PushStatement(&cg->treeContext, &stmtInfo,
+ pn->pn_kid3 ? STMT_FINALLY : STMT_BLOCK,
+ CG_OFFSET(cg));
+
+ /*
+ * About JSOP_SETSP: an exception can be thrown while the stack is in
+ * an unbalanced state, and this imbalance causes problems with things
+ * like function invocation later on.
+ *
+ * To fix this, we compute the `balanced' stack depth upon try entry,
+ * and then restore the stack to this depth when we hit the first catch
+ * or finally block. We can't just zero the stack, because things like
+ * for/in and with that are active upon entry to the block keep state
+ * variables on the stack.
+ */
+ depth = cg->stackDepth;
+
+ /* Mark try location for decompilation, then emit try block. */
+ if (js_Emit1(cx, cg, JSOP_TRY) < 0)
+ return JS_FALSE;
+ start = CG_OFFSET(cg);
+ if (!js_EmitTree(cx, cg, pn->pn_kid1))
+ return JS_FALSE;
+
+ /* GOSUB to finally, if present. */
+ if (pn->pn_kid3) {
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
+ return JS_FALSE;
+ EMIT_FINALLY_GOSUB(cx, cg, jmp);
+ if (jmp < 0)
+ return JS_FALSE;
+ }
+
+ /* Emit (hidden) jump over catch and/or finally. */
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
+ return JS_FALSE;
+ EMIT_CATCH_GOTO(cx, cg, jmp);
+ if (jmp < 0)
+ return JS_FALSE;
+
+ end = CG_OFFSET(cg);
+
+ /* If this try has a catch block, emit it. */
+ iter = pn->pn_kid2;
+ if (iter) {
+ catchStart = end;
+
+ /*
+ * The emitted code for a catch block looks like:
+ *
+ * [ popscope ] only if 2nd+ catch block
+ * name Object
+ * pushobj
+ * newinit
+ * exception
+ * initcatchvar <atom>
+ * enterwith
+ * [< catchguard code >] if there's a catchguard
+ * [ifeq <offset to next catch block>] " "
+ * < catch block contents >
+ * leavewith
+ * goto <end of catch blocks> non-local; finally applies
+ *
+ * If there's no catch block without a catchguard, the last
+ * <offset to next catch block> points to rethrow code. This
+ * code will GOSUB to the finally code if appropriate, and is
+ * also used for the catch-all trynote for capturing exceptions
+ * thrown from catch{} blocks.
+ */
+ for (;;) {
+ JSStmtInfo stmtInfo2;
+ JSParseNode *disc;
+ ptrdiff_t guardnote;
+
+ if (!UpdateLineNumberNotes(cx, cg, iter))
+ return JS_FALSE;
+
+ if (catchJump != -1) {
+ /* Fix up and clean up previous catch block. */
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump);
+
+ /* Compensate for the [leavewith]. */
+ cg->stackDepth++;
+ JS_ASSERT((uintN) cg->stackDepth <= cg->maxStackDepth);
+
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
+ js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) {
+ return JS_FALSE;
+ }
+ } else {
+ /* Set stack to original depth (see SETSP comment above). */
+ EMIT_ATOM_INDEX_OP(JSOP_SETSP, (jsatomid)depth);
+ cg->stackDepth = depth;
+ }
+
+ /* Non-negative guardnote offset is length of catchguard. */
+ guardnote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0);
+ if (guardnote < 0 ||
+ js_Emit1(cx, cg, JSOP_NOP) < 0) {
+ return JS_FALSE;
+ }
+
+ /* Construct the scope holder and push it on. */
+ ale = js_IndexAtom(cx, cx->runtime->atomState.ObjectAtom,
+ &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(JSOP_NAME, ALE_INDEX(ale));
+
+ if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0 ||
+ js_Emit1(cx, cg, JSOP_NEWINIT) < 0 ||
+ js_Emit1(cx, cg, JSOP_EXCEPTION) < 0) {
+ return JS_FALSE;
+ }
+
+ /* initcatchvar <atomIndex> */
+ disc = iter->pn_kid1;
+ ale = js_IndexAtom(cx, disc->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+
+ EMIT_ATOM_INDEX_OP(JSOP_INITCATCHVAR, ALE_INDEX(ale));
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
+ js_Emit1(cx, cg, JSOP_ENTERWITH) < 0) {
+ return JS_FALSE;
+ }
+
+ /* boolean_expr */
+ if (disc->pn_expr) {
+ ptrdiff_t guardstart = CG_OFFSET(cg);
+ if (!js_EmitTree(cx, cg, disc->pn_expr))
+ return JS_FALSE;
+ if (!js_SetSrcNoteOffset(cx, cg, guardnote, 0,
+ CG_OFFSET(cg) - guardstart)) {
+ return JS_FALSE;
+ }
+ /* ifeq <next block> */
+ catchJump = EmitJump(cx, cg, JSOP_IFEQ, 0);
+ if (catchJump < 0)
+ return JS_FALSE;
+ }
+
+ /* Emit catch block. */
+ js_PushStatement(&cg->treeContext, &stmtInfo2, STMT_CATCH,
+ CG_OFFSET(cg));
+ stmtInfo2.label = disc->pn_atom;
+ if (!js_EmitTree(cx, cg, iter->pn_kid3))
+ return JS_FALSE;
+ js_PopStatementCG(cx, cg);
+
+ /*
+ * Jump over the remaining catch blocks.
+ * This counts as a non-local jump, so do the finally thing.
+ */
+
+ /* popscope */
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
+ js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) {
+ return JS_FALSE;
+ }
+
+ /* gosub <finally>, if required */
+ if (pn->pn_kid3) {
+ EMIT_FINALLY_GOSUB(cx, cg, jmp);
+ if (jmp < 0)
+ return JS_FALSE;
+ }
+
+ /* This will get fixed up to jump to after catch/finally. */
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
+ return JS_FALSE;
+ EMIT_CATCH_GOTO(cx, cg, jmp);
+ if (jmp < 0)
+ return JS_FALSE;
+ if (!iter->pn_kid2) /* leave iter at last catch */
+ break;
+ iter = iter->pn_kid2;
+ }
+ }
+
+ /*
+ * We use a [leavewith],[gosub],rethrow block for rethrowing
+ * when there's no unguarded catch, and also for running finally
+ * code while letting an uncaught exception pass through.
+ */
+ if (pn->pn_kid3 ||
+ (catchJump != -1 && iter->pn_kid1->pn_expr)) {
+ /*
+ * Emit another stack fixup, because the catch could itself
+ * throw an exception in an unbalanced state, and the finally
+ * may need to call functions. If there is no finally, only
+ * guarded catches, the rethrow code below nevertheless needs
+ * stack fixup.
+ */
+ finallyCatch = CG_OFFSET(cg);
+ EMIT_ATOM_INDEX_OP(JSOP_SETSP, (jsatomid)depth);
+ cg->stackDepth = depth;
+
+ /* Last discriminant jumps to rethrow if none match. */
+ if (catchJump != -1 && iter->pn_kid1->pn_expr) {
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump);
+
+ /* Compensate for the [leavewith]. */
+ cg->stackDepth++;
+ JS_ASSERT((uintN) cg->stackDepth <= cg->maxStackDepth);
+
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
+ js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) {
+ return JS_FALSE;
+ }
+ }
+
+ if (pn->pn_kid3) {
+ EMIT_FINALLY_GOSUB(cx, cg, jmp);
+ if (jmp < 0)
+ return JS_FALSE;
+ cg->stackDepth = depth;
+ }
+
+ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
+ js_Emit1(cx, cg, JSOP_EXCEPTION) < 0 ||
+ js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
+ js_Emit1(cx, cg, JSOP_THROW) < 0) {
+ return JS_FALSE;
+ }
+ JS_ASSERT(cg->stackDepth == depth);
+ }
+
+ /*
+ * If we have a finally, it belongs here, and we have to fix up the
+ * gosubs that might have been emitted before non-local jumps.
+ */
+ if (pn->pn_kid3) {
+ if (!BackPatch(cx, cg, stmtInfo.gosub, CG_NEXT(cg), JSOP_GOSUB))
+ return JS_FALSE;
+
+ /*
+ * The stack budget must be balanced at this point, and we need
+ * one more slot for the JSOP_RETSUB return address pushed by a
+ * JSOP_GOSUB opcode that calls this finally clause.
+ */
+ JS_ASSERT(cg->stackDepth == depth);
+ if ((uintN)++cg->stackDepth > cg->maxStackDepth)
+ cg->maxStackDepth = cg->stackDepth;
+
+ /* Now indicate that we're emitting a subroutine body. */
+ stmtInfo.type = STMT_SUBROUTINE;
+ if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 ||
+ !js_EmitTree(cx, cg, pn->pn_kid3) ||
+ js_Emit1(cx, cg, JSOP_RETSUB) < 0) {
+ return JS_FALSE;
+ }
+ }
+ js_PopStatementCG(cx, cg);
+
+ if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
+ js_Emit1(cx, cg, JSOP_NOP) < 0) {
+ return JS_FALSE;
+ }
+
+ /* Fix up the end-of-try/catch jumps to come here. */
+ if (!BackPatch(cx, cg, stmtInfo.catchJump, CG_NEXT(cg), JSOP_GOTO))
+ return JS_FALSE;
+
+ /*
+ * Add the try note last, to let post-order give us the right ordering
+ * (first to last for a given nesting level, inner to outer by level).
+ */
+ if (pn->pn_kid2) {
+ JS_ASSERT(end != -1 && catchStart != -1);
+ if (!js_NewTryNote(cx, cg, start, end, catchStart))
+ return JS_FALSE;
+ }
+
+ /*
+ * If we've got a finally, mark try+catch region with additional
+ * trynote to catch exceptions (re)thrown from a catch block or
+ * for the try{}finally{} case.
+ */
+ if (pn->pn_kid3) {
+ JS_ASSERT(finallyCatch != -1);
+ if (!js_NewTryNote(cx, cg, start, finallyCatch, finallyCatch))
+ return JS_FALSE;
+ }
+ break;
+ }
+
+#endif /* JS_HAS_EXCEPTIONS */
+
+ case TOK_VAR:
+ off = noteIndex = -1;
+ for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {
+ JS_ASSERT(pn2->pn_type == TOK_NAME);
+ if (!LookupArgOrVar(cx, &cg->treeContext, pn2))
+ return JS_FALSE;
+ op = pn2->pn_op;
+ if (op == JSOP_ARGUMENTS) {
+ JS_ASSERT(!pn2->pn_expr); /* JSOP_ARGUMENTS => no initializer */
+#ifdef __GNUC__
+ atomIndex = 0; /* quell GCC overwarning */
+#endif
+ } else {
+ if (pn2->pn_slot >= 0) {
+ atomIndex = (jsatomid) pn2->pn_slot;
+ } else {
+ ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ atomIndex = ALE_INDEX(ale);
+
+ if (!(cg->treeContext.flags & TCF_IN_FUNCTION) ||
+ (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)) {
+ /* Emit a prolog bytecode to predefine the variable. */
+ CG_SWITCH_TO_PROLOG(cg);
+ if (!UpdateLineNumberNotes(cx, cg, pn2))
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(pn->pn_op, atomIndex);
+ CG_SWITCH_TO_MAIN(cg);
+ }
+ }
+ if (pn2->pn_expr) {
+ if (op == JSOP_SETNAME)
+ EMIT_ATOM_INDEX_OP(JSOP_BINDNAME, atomIndex);
+ if (!js_EmitTree(cx, cg, pn2->pn_expr))
+ return JS_FALSE;
+ }
+ }
+ if (pn2 == pn->pn_head &&
+ js_NewSrcNote(cx, cg,
+ (pn->pn_op == JSOP_DEFCONST)
+ ? SRC_CONST
+ : SRC_VAR) < 0) {
+ return JS_FALSE;
+ }
+ if (op == JSOP_ARGUMENTS) {
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ } else {
+ EMIT_ATOM_INDEX_OP(op, atomIndex);
+ }
+ tmp = CG_OFFSET(cg);
+ if (noteIndex >= 0) {
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
+ return JS_FALSE;
+ }
+ if (!pn2->pn_next)
+ break;
+ off = tmp;
+ noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
+ if (noteIndex < 0 ||
+ js_Emit1(cx, cg, JSOP_POP) < 0) {
+ return JS_FALSE;
+ }
+ }
+ if (pn->pn_extra) {
+ if (js_Emit1(cx, cg, JSOP_POP) < 0)
+ return JS_FALSE;
+ }
+ break;
+
+ case TOK_RETURN:
+ /* Push a return value */
+ pn2 = pn->pn_kid;
+ if (pn2) {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ } else {
+ if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
+ return JS_FALSE;
+ }
+
+ /*
+ * EmitNonLocalJumpFixup mutates op to JSOP_RETRVAL after emitting a
+ * JSOP_SETRVAL if there are open try blocks having finally clauses.
+ * We can't simply transfer control flow to our caller in that case,
+ * because we must gosub to those clauses from inner to outer, with
+ * the correct stack pointer (i.e., after popping any with, for/in,
+ * etc., slots nested inside the finally's try).
+ */
+ op = JSOP_RETURN;
+ if (!EmitNonLocalJumpFixup(cx, cg, NULL, &op))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ break;
+
+ case TOK_LC:
+ js_PushStatement(&cg->treeContext, &stmtInfo, STMT_BLOCK, top);
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ }
+ ok = js_PopStatementCG(cx, cg);
+ break;
+
+ case TOK_SEMI:
+ pn2 = pn->pn_kid;
+ if (pn2) {
+ /*
+ * Top-level or called-from-a-native JS_Execute/EvaluateScript,
+ * debugger, and eval frames may need the value of the ultimate
+ * expression statement as the script's result, despite the fact
+ * that it appears useless to the compiler.
+ */
+ useful = wantval = !cx->fp->fun ||
+ cx->fp->fun->native ||
+ (cx->fp->flags & JSFRAME_SPECIAL);
+ if (!useful) {
+ if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))
+ return JS_FALSE;
+ }
+ if (!useful) {
+ CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno;
+ if (!js_ReportCompileErrorNumber(cx, NULL, cg,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_USELESS_EXPR)) {
+ return JS_FALSE;
+ }
+ } else {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, wantval ? JSOP_POPV : JSOP_POP) < 0)
+ return JS_FALSE;
+ }
+ }
+ break;
+
+ case TOK_COLON:
+ /* Emit an annotated nop so we know to decompile a label. */
+ atom = pn->pn_atom;
+ ale = js_IndexAtom(cx, atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ pn2 = pn->pn_expr;
+ noteIndex = js_NewSrcNote2(cx, cg,
+ (pn2->pn_type == TOK_LC)
+ ? SRC_LABELBRACE
+ : SRC_LABEL,
+ (ptrdiff_t) ALE_INDEX(ale));
+ if (noteIndex < 0 ||
+ js_Emit1(cx, cg, JSOP_NOP) < 0) {
+ return JS_FALSE;
+ }
+
+ /* Emit code for the labeled statement. */
+ js_PushStatement(&cg->treeContext, &stmtInfo, STMT_LABEL,
+ CG_OFFSET(cg));
+ stmtInfo.label = atom;
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ if (!js_PopStatementCG(cx, cg))
+ return JS_FALSE;
+
+ /* If the statement was compound, emit a note for the end brace. */
+ if (pn2->pn_type == TOK_LC) {
+ if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
+ js_Emit1(cx, cg, JSOP_NOP) < 0) {
+ return JS_FALSE;
+ }
+ }
+ break;
+
+ case TOK_COMMA:
+ /*
+ * Emit SRC_PCDELTA notes on each JSOP_POP between comma operands.
+ * These notes help the decompiler bracket the bytecodes generated
+ * from each sub-expression that follows a comma.
+ */
+ off = noteIndex = -1;
+ for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ tmp = CG_OFFSET(cg);
+ if (noteIndex >= 0) {
+ if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
+ return JS_FALSE;
+ }
+ if (!pn2->pn_next)
+ break;
+ off = tmp;
+ noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
+ if (noteIndex < 0 ||
+ js_Emit1(cx, cg, JSOP_POP) < 0) {
+ return JS_FALSE;
+ }
+ }
+ break;
+
+ case TOK_ASSIGN:
+ /*
+ * Check left operand type and generate specialized code for it.
+ * Specialize to avoid ECMA "reference type" values on the operand
+ * stack, which impose pervasive runtime "GetValue" costs.
+ */
+ pn2 = pn->pn_left;
+ JS_ASSERT(pn2->pn_type != TOK_RP);
+ atomIndex = (jsatomid) -1; /* Suppress warning. */
+ switch (pn2->pn_type) {
+ case TOK_NAME:
+ if (!LookupArgOrVar(cx, &cg->treeContext, pn2))
+ return JS_FALSE;
+ if (pn2->pn_slot >= 0) {
+ atomIndex = (jsatomid) pn2->pn_slot;
+ } else {
+ ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ atomIndex = ALE_INDEX(ale);
+ EMIT_ATOM_INDEX_OP(JSOP_BINDNAME, atomIndex);
+ }
+ break;
+ case TOK_DOT:
+ if (!js_EmitTree(cx, cg, pn2->pn_expr))
+ return JS_FALSE;
+ ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ atomIndex = ALE_INDEX(ale);
+ break;
+ case TOK_LB:
+ JS_ASSERT(pn->pn_arity == PN_BINARY);
+ if (!js_EmitTree(cx, cg, pn2->pn_left))
+ return JS_FALSE;
+ if (!js_EmitTree(cx, cg, pn2->pn_right))
+ return JS_FALSE;
+ break;
+#if JS_HAS_LVALUE_RETURN
+ case TOK_LP:
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ break;
+#endif
+ default:
+ JS_ASSERT(0);
+ }
+
+ op = pn->pn_op;
+#if JS_HAS_GETTER_SETTER
+ if (op == JSOP_GETTER || op == JSOP_SETTER) {
+ /* We'll emit these prefix bytecodes after emitting the r.h.s. */
+ } else
+#endif
+ /* If += or similar, dup the left operand and get its value. */
+ if (op != JSOP_NOP) {
+ switch (pn2->pn_type) {
+ case TOK_NAME:
+ if (pn2->pn_op != JSOP_SETNAME) {
+ EMIT_ATOM_INDEX_OP((pn2->pn_op == JSOP_SETARG)
+ ? JSOP_GETARG
+ : JSOP_GETVAR,
+ atomIndex);
+ break;
+ }
+ /* FALL THROUGH */
+ case TOK_DOT:
+ if (js_Emit1(cx, cg, JSOP_DUP) < 0)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(JSOP_GETPROP, atomIndex);
+ break;
+ case TOK_LB:
+#if JS_HAS_LVALUE_RETURN
+ case TOK_LP:
+#endif
+ if (js_Emit1(cx, cg, JSOP_DUP2) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
+ return JS_FALSE;
+ break;
+ default:;
+ }
+ }
+
+ /* Now emit the right operand (it may affect the namespace). */
+ if (!js_EmitTree(cx, cg, pn->pn_right))
+ return JS_FALSE;
+
+ /* If += etc., emit the binary operator with a decompiler note. */
+ if (op != JSOP_NOP) {
+ if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0 ||
+ js_Emit1(cx, cg, op) < 0) {
+ return JS_FALSE;
+ }
+ }
+
+ /* Left parts such as a.b.c and a[b].c need a decompiler note. */
+ if (pn2->pn_type != TOK_NAME) {
+ if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
+ return JS_FALSE;
+ }
+
+ /* Finally, emit the specialized assignment bytecode. */
+ switch (pn2->pn_type) {
+ case TOK_NAME:
+ if (pn2->pn_slot < 0 || !(pn2->pn_attrs & JSPROP_READONLY)) {
+ case TOK_DOT:
+ EMIT_ATOM_INDEX_OP(pn2->pn_op, atomIndex);
+ }
+ break;
+ case TOK_LB:
+#if JS_HAS_LVALUE_RETURN
+ case TOK_LP:
+#endif
+ if (js_Emit1(cx, cg, JSOP_SETELEM) < 0)
+ return JS_FALSE;
+ break;
+ default:;
+ }
+ break;
+
+ case TOK_HOOK:
+ /* Emit the condition, then branch if false to the else part. */
+ if (!js_EmitTree(cx, cg, pn->pn_kid1))
+ return JS_FALSE;
+ noteIndex = js_NewSrcNote(cx, cg, SRC_COND);
+ if (noteIndex < 0)
+ return JS_FALSE;
+ beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
+ if (beq < 0 || !js_EmitTree(cx, cg, pn->pn_kid2))
+ return JS_FALSE;
+
+ /* Jump around else, fixup the branch, emit else, fixup jump. */
+ jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
+ if (jmp < 0)
+ return JS_FALSE;
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
+ if (!js_EmitTree(cx, cg, pn->pn_kid3))
+ return JS_FALSE;
+ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
+ if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
+ return JS_FALSE;
+
+ /*
+ * Because each branch pushes a single value, but our stack budgeting
+ * analysis ignores branches, we now have two values accounted for in
+ * cg->stackDepth. Execution will follow only one path, so we must
+ * decrement cg->stackDepth here. Failing to do this will foil code,
+ * such as the try/catch/finally exception handling code generator,
+ * that samples cg->stackDepth for use at runtime (JSOP_SETSP).
+ */
+ JS_ASSERT(cg->stackDepth > 1);
+ cg->stackDepth--;
+ break;
+
+ case TOK_OR:
+ case TOK_AND:
+ /*
+ * JSOP_OR converts the operand on the stack to boolean, and if true,
+ * leaves the original operand value on the stack and jumps; otherwise
+ * it pops and falls into the next bytecode, which evaluates the right
+ * operand. The jump goes around the right operand evaluation.
+ *
+ * JSOP_AND converts the operand on the stack to boolean, and if false,
+ * leaves the original operand value on the stack and jumps; otherwise
+ * it pops and falls into the right operand's bytecode.
+ *
+ * Avoid tail recursion for long ||...|| expressions and long &&...&&
+ * expressions or long mixtures of ||'s and &&'s that can easily blow
+ * the stack, by forward-linking and then backpatching all the JSOP_OR
+ * and JSOP_AND bytecodes' immediate jump-offset operands.
+ */
+ pn3 = pn;
+ if (!js_EmitTree(cx, cg, pn->pn_left))
+ return JS_FALSE;
+ top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
+ if (top < 0)
+ return JS_FALSE;
+ jmp = top;
+ pn2 = pn->pn_right;
+ while (pn2->pn_type == TOK_OR || pn2->pn_type == TOK_AND) {
+ pn = pn2;
+ if (!js_EmitTree(cx, cg, pn->pn_left))
+ return JS_FALSE;
+ off = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
+ if (off < 0)
+ return JS_FALSE;
+ if (!SetBackPatchDelta(cx, cg, CG_CODE(cg, jmp), off - jmp))
+ return JS_FALSE;
+ jmp = off;
+ pn2 = pn->pn_right;
+ }
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ off = CG_OFFSET(cg);
+ do {
+ pc = CG_CODE(cg, top);
+ tmp = GetJumpOffset(cg, pc);
+ CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
+ *pc = pn3->pn_op;
+ top += tmp;
+ } while ((pn3 = pn3->pn_right) != pn2);
+ break;
+
+ case TOK_BITOR:
+ case TOK_BITXOR:
+ case TOK_BITAND:
+ case TOK_EQOP:
+ case TOK_RELOP:
+#if JS_HAS_IN_OPERATOR
+ case TOK_IN:
+#endif
+#if JS_HAS_INSTANCEOF
+ case TOK_INSTANCEOF:
+#endif
+ case TOK_SHOP:
+ case TOK_PLUS:
+ case TOK_MINUS:
+ case TOK_STAR:
+ case TOK_DIVOP:
+ if (pn->pn_arity == PN_LIST) {
+ /* Left-associative operator chain: avoid too much recursion. */
+ pn2 = pn->pn_head;
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ op = pn->pn_op;
+ while ((pn2 = pn2->pn_next) != NULL) {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ }
+ } else {
+ /* Binary operators that evaluate both operands unconditionally. */
+ if (!js_EmitTree(cx, cg, pn->pn_left))
+ return JS_FALSE;
+ if (!js_EmitTree(cx, cg, pn->pn_right))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, pn->pn_op) < 0)
+ return JS_FALSE;
+ }
+ break;
+
+#if JS_HAS_EXCEPTIONS
+ case TOK_THROW:
+#endif
+ case TOK_UNARYOP:
+ /* Unary op, including unary +/-. */
+ if (!js_EmitTree(cx, cg, pn->pn_kid))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, pn->pn_op) < 0)
+ return JS_FALSE;
+ break;
+
+ case TOK_INC:
+ case TOK_DEC:
+ /* Emit lvalue-specialized code for ++/-- operators. */
+ pn2 = pn->pn_kid;
+ JS_ASSERT(pn2->pn_type != TOK_RP);
+ op = pn->pn_op;
+ switch (pn2->pn_type) {
+ case TOK_NAME:
+ pn2->pn_op = op;
+ if (!LookupArgOrVar(cx, &cg->treeContext, pn2))
+ return JS_FALSE;
+ op = pn2->pn_op;
+ if (pn2->pn_slot >= 0) {
+ if (pn2->pn_attrs & JSPROP_READONLY)
+ op = JSOP_GETVAR;
+ atomIndex = (jsatomid) pn2->pn_slot;
+ EMIT_ATOM_INDEX_OP(op, atomIndex);
+ } else {
+ if (!EmitAtomOp(cx, pn2, op, cg))
+ return JS_FALSE;
+ }
+ break;
+ case TOK_DOT:
+ if (!EmitPropOp(cx, pn2, op, cg))
+ return JS_FALSE;
+ break;
+ case TOK_LB:
+ if (!EmitElemOp(cx, pn2, op, cg))
+ return JS_FALSE;
+ break;
+#if JS_HAS_LVALUE_RETURN
+ case TOK_LP:
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
+ CG_OFFSET(cg) - pn2->pn_offset) < 0) {
+ return JS_FALSE;
+ }
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ break;
+#endif
+ default:
+ JS_ASSERT(0);
+ }
+ break;
+
+ case TOK_DELETE:
+ /* Under ECMA 3, deleting a non-reference returns true. */
+ pn2 = pn->pn_kid;
+ switch (pn2->pn_type) {
+ case TOK_NAME:
+ pn2->pn_op = JSOP_DELNAME;
+ if (!LookupArgOrVar(cx, &cg->treeContext, pn2))
+ return JS_FALSE;
+ op = pn2->pn_op;
+ if (op == JSOP_FALSE) {
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ } else {
+ if (!EmitAtomOp(cx, pn2, op, cg))
+ return JS_FALSE;
+ }
+ break;
+ case TOK_DOT:
+ if (!EmitPropOp(cx, pn2, JSOP_DELPROP, cg))
+ return JS_FALSE;
+ break;
+ case TOK_LB:
+ if (!EmitElemOp(cx, pn2, JSOP_DELELEM, cg))
+ return JS_FALSE;
+ break;
+ default:
+ if (js_Emit1(cx, cg, JSOP_TRUE) < 0)
+ return JS_FALSE;
+ }
+ break;
+
+ case TOK_DOT:
+ /*
+ * Pop a stack operand, convert it to object, get a property named by
+ * this bytecode's immediate-indexed atom operand, and push its value
+ * (not a reference to it). This bytecode sets the virtual machine's
+ * "obj" register to the left operand's ToObject conversion result,
+ * for use by JSOP_PUSHOBJ.
+ */
+ ok = EmitPropOp(cx, pn, pn->pn_op, cg);
+ break;
+
+ case TOK_LB:
+ /*
+ * Pop two operands, convert the left one to object and the right one
+ * to property name (atom or tagged int), get the named property, and
+ * push its value. Set the "obj" register to the result of ToObject
+ * on the left operand.
+ */
+ ok = EmitElemOp(cx, pn, pn->pn_op, cg);
+ break;
+
+ case TOK_NEW:
+ case TOK_LP:
+ /*
+ * Emit function call or operator new (constructor call) code.
+ * First, emit code for the left operand to evaluate the callable or
+ * constructable object expression.
+ */
+ pn2 = pn->pn_head;
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+
+ /* Remember start of callable-object bytecode for decompilation hint. */
+ off = pn2->pn_offset;
+
+ /*
+ * Push the virtual machine's "obj" register, which was set by a name,
+ * property, or element get (or set) bytecode.
+ */
+ if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
+ return JS_FALSE;
+
+ /*
+ * Emit code for each argument in order, then emit the JSOP_*CALL or
+ * JSOP_NEW bytecode with a two-byte immediate telling how many args
+ * were pushed on the operand stack.
+ */
+ for (pn2 = pn2->pn_next; pn2; pn2 = pn2->pn_next) {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ }
+ if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
+ return JS_FALSE;
+ argc = pn->pn_count - 1;
+ if (js_Emit3(cx, cg, pn->pn_op, ARGC_HI(argc), ARGC_LO(argc)) < 0)
+ return JS_FALSE;
+ break;
+
+#if JS_HAS_INITIALIZERS
+ case TOK_RB:
+ /*
+ * Emit code for [a, b, c] of the form:
+ * t = new Array; t[0] = a; t[1] = b; t[2] = c; t;
+ * but use a stack slot for t and avoid dup'ing and popping it via
+ * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.
+ */
+ ale = js_IndexAtom(cx, cx->runtime->atomState.ArrayAtom,
+ &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(JSOP_NAME, ALE_INDEX(ale));
+ if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)
+ return JS_FALSE;
+
+ pn2 = pn->pn_head;
+#if JS_HAS_SHARP_VARS
+ if (pn2 && pn2->pn_type == TOK_DEFSHARP) {
+ EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
+ pn2 = pn2->pn_next;
+ }
+#endif
+
+ for (atomIndex = 0; pn2; pn2 = pn2->pn_next) {
+ /* PrimaryExpr enforced ATOM_INDEX_LIMIT, so in-line optimize. */
+ JS_ASSERT(atomIndex < ATOM_INDEX_LIMIT);
+ if (atomIndex == 0) {
+ if (js_Emit1(cx, cg, JSOP_ZERO) < 0)
+ return JS_FALSE;
+ } else if (atomIndex == 1) {
+ if (js_Emit1(cx, cg, JSOP_ONE) < 0)
+ return JS_FALSE;
+ } else {
+ EMIT_ATOM_INDEX_OP(JSOP_UINT16, (jsatomid)atomIndex);
+ }
+
+ /* Sub-optimal: holes in a sparse initializer are void-filled. */
+ if (pn2->pn_type == TOK_COMMA) {
+ if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
+ return JS_FALSE;
+ } else {
+ if (!js_EmitTree(cx, cg, pn2))
+ return JS_FALSE;
+ }
+ if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
+ return JS_FALSE;
+
+ atomIndex++;
+ }
+
+ if (pn->pn_extra) {
+ /* Emit a source note so we know to decompile an extra comma. */
+ if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)
+ return JS_FALSE;
+ }
+
+ /* Emit an op for sharp array cleanup and decompilation. */
+ if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
+ return JS_FALSE;
+ break;
+
+ case TOK_RC:
+ /*
+ * Emit code for {p:a, '%q':b, 2:c} of the form:
+ * t = new Object; t.p = a; t['%q'] = b; t[2] = c; t;
+ * but use a stack slot for t and avoid dup'ing and popping it via
+ * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.
+ */
+ ale = js_IndexAtom(cx, cx->runtime->atomState.ObjectAtom,
+ &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(JSOP_NAME, ALE_INDEX(ale));
+
+ if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)
+ return JS_FALSE;
+
+ pn2 = pn->pn_head;
+#if JS_HAS_SHARP_VARS
+ if (pn2 && pn2->pn_type == TOK_DEFSHARP) {
+ EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
+ pn2 = pn2->pn_next;
+ }
+#endif
+
+ for (; pn2; pn2 = pn2->pn_next) {
+ /* Emit an index for t[2], else map an atom for t.p or t['%q']. */
+ pn3 = pn2->pn_left;
+ switch (pn3->pn_type) {
+ case TOK_NUMBER:
+ if (!EmitNumberOp(cx, pn3->pn_dval, cg))
+ return JS_FALSE;
+ break;
+ case TOK_NAME:
+ case TOK_STRING:
+ ale = js_IndexAtom(cx, pn3->pn_atom, &cg->atomList);
+ if (!ale)
+ return JS_FALSE;
+ break;
+ default:
+ JS_ASSERT(0);
+ }
+
+ /* Emit code for the property initializer. */
+ if (!js_EmitTree(cx, cg, pn2->pn_right))
+ return JS_FALSE;
+
+#if JS_HAS_GETTER_SETTER
+ op = pn2->pn_op;
+ if (op == JSOP_GETTER || op == JSOP_SETTER) {
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ }
+#endif
+ /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
+ if (pn3->pn_type == TOK_NUMBER) {
+ if (js_NewSrcNote(cx, cg, SRC_LABEL) < 0)
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
+ return JS_FALSE;
+ } else {
+ EMIT_ATOM_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));
+ }
+ }
+
+ /* Emit an op for sharpArray cleanup and decompilation. */
+ if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
+ return JS_FALSE;
+ break;
+
+#if JS_HAS_SHARP_VARS
+ case TOK_DEFSHARP:
+ if (!js_EmitTree(cx, cg, pn->pn_kid))
+ return JS_FALSE;
+ EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num);
+ break;
+
+ case TOK_USESHARP:
+ EMIT_ATOM_INDEX_OP(JSOP_USESHARP, (jsatomid) pn->pn_num);
+ break;
+#endif /* JS_HAS_SHARP_VARS */
+#endif /* JS_HAS_INITIALIZERS */
+
+ case TOK_RP:
+ /*
+ * The node for (e) has e as its kid, enabling users who want to nest
+ * assignment expressions in conditions to avoid the error correction
+ * done by Condition (from x = y to x == y) by double-parenthesizing.
+ */
+ if (!js_EmitTree(cx, cg, pn->pn_kid))
+ return JS_FALSE;
+ if (js_Emit1(cx, cg, JSOP_GROUP) < 0)
+ return JS_FALSE;
+ break;
+
+ case TOK_NAME:
+ if (!LookupArgOrVar(cx, &cg->treeContext, pn))
+ return JS_FALSE;
+ op = pn->pn_op;
+ if (op == JSOP_ARGUMENTS) {
+ if (js_Emit1(cx, cg, op) < 0)
+ return JS_FALSE;
+ break;
+ }
+ if (pn->pn_slot >= 0) {
+ atomIndex = (jsatomid) pn->pn_slot;
+ EMIT_ATOM_INDEX_OP(op, atomIndex);
+ break;
+ }
+ /* FALL THROUGH */
+ case TOK_STRING:
+ case TOK_OBJECT:
+ /*
+ * The scanner and parser associate JSOP_NAME with TOK_NAME, although
+ * other bytecodes may result instead (JSOP_BINDNAME/JSOP_SETNAME,
+ * JSOP_FORNAME, etc.). Among JSOP_*NAME* variants, only JSOP_NAME
+ * may generate the first operand of a call or new expression, so only
+ * it sets the "obj" virtual machine register to the object along the
+ * scope chain in which the name was found.
+ *
+ * Token types for STRING and OBJECT have corresponding bytecode ops
+ * in pn_op and emit the same format as NAME, so they share this code.
+ */
+ ok = EmitAtomOp(cx, pn, pn->pn_op, cg);
+ break;
+
+ case TOK_NUMBER:
+ ok = EmitNumberOp(cx, pn->pn_dval, cg);
+ break;
+
+ case TOK_PRIMARY:
+ if (js_Emit1(cx, cg, pn->pn_op) < 0)
+ return JS_FALSE;
+ break;
+
+#if JS_HAS_DEBUGGER_KEYWORD
+ case TOK_DEBUGGER:
+ if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0)
+ return JS_FALSE;
+ break;
+#endif /* JS_HAS_DEBUGGER_KEYWORD */
+
+ default:
+ JS_ASSERT(0);
+ }
+
+ if (ok && --cg->emitLevel == 0 && cg->spanDeps)
+ ok = OptimizeSpanDeps(cx, cg);
+
+ return ok;
+}
+
+JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
+ {"null", 0, 0, 0},
+ {"if", 0, 0, 0},
+ {"if-else", 1, 0, 1},
+ {"while", 1, 0, 1},
+ {"for", 3, 1, 1},
+ {"continue", 0, 0, 0},
+ {"var", 0, 0, 0},
+ {"pcdelta", 1, 0, 1},
+ {"assignop", 0, 0, 0},
+ {"cond", 1, 0, 1},
+ {"reserved0", 0, 0, 0},
+ {"hidden", 0, 0, 0},
+ {"pcbase", 1, 0, -1},
+ {"label", 1, 0, 0},
+ {"labelbrace", 1, 0, 0},
+ {"endbrace", 0, 0, 0},
+ {"break2label", 1, 0, 0},
+ {"cont2label", 1, 0, 0},
+ {"switch", 2, 0, 1},
+ {"funcdef", 1, 0, 0},
+ {"catch", 1, 11, 1},
+ {"const", 0, 0, 0},
+ {"newline", 0, 0, 0},
+ {"setline", 1, 0, 0},
+ {"xdelta", 0, 0, 0},
+};
+
+static intN
+AllocSrcNote(JSContext *cx, JSCodeGenerator *cg)
+{
+ intN index;
+ JSArenaPool *pool;
+ size_t size;
+
+ index = CG_NOTE_COUNT(cg);
+ if (((uintN)index & CG_NOTE_MASK(cg)) == 0) {
+ pool = cg->notePool;
+ size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1);
+ if (!CG_NOTES(cg)) {
+ /* Allocate the first note array lazily; leave noteMask alone. */
+ JS_ARENA_ALLOCATE_CAST(CG_NOTES(cg), jssrcnote *, pool, size);
+ } else {
+ /* Grow by doubling note array size; update noteMask on success. */
+ JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size);
+ if (CG_NOTES(cg))
+ CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1;
+ }
+ if (!CG_NOTES(cg)) {
+ JS_ReportOutOfMemory(cx);
+ return -1;
+ }
+ }
+
+ CG_NOTE_COUNT(cg) = index + 1;
+ return index;
+}
+
+intN
+js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type)
+{
+ intN index, n;
+ jssrcnote *sn;
+ ptrdiff_t offset, delta, xdelta;
+
+ /*
+ * Claim a note slot in CG_NOTES(cg) by growing it if necessary and then
+ * incrementing CG_NOTE_COUNT(cg).
+ */
+ index = AllocSrcNote(cx, cg);
+ if (index < 0)
+ return -1;
+ sn = &CG_NOTES(cg)[index];
+
+ /*
+ * Compute delta from the last annotated bytecode's offset. If it's too
+ * big to fit in sn, allocate one or more xdelta notes and reset sn.
+ */
+ offset = CG_OFFSET(cg);
+ delta = offset - CG_LAST_NOTE_OFFSET(cg);
+ CG_LAST_NOTE_OFFSET(cg) = offset;
+ if (delta >= SN_DELTA_LIMIT) {
+ do {
+ xdelta = JS_MIN(delta, SN_XDELTA_MASK);
+ SN_MAKE_XDELTA(sn, xdelta);
+ delta -= xdelta;
+ index = AllocSrcNote(cx, cg);
+ if (index < 0)
+ return -1;
+ sn = &CG_NOTES(cg)[index];
+ } while (delta >= SN_DELTA_LIMIT);
+ }
+
+ /*
+ * Initialize type and delta, then allocate the minimum number of notes
+ * needed for type's arity. Usually, we won't need more, but if an offset
+ * does take two bytes, js_SetSrcNoteOffset will grow CG_NOTES(cg).
+ */
+ SN_MAKE_NOTE(sn, type, delta);
+ for (n = (intN)js_SrcNoteSpec[type].arity; n > 0; n--) {
+ if (js_NewSrcNote(cx, cg, SRC_NULL) < 0)
+ return -1;
+ }
+ return index;
+}
+
+intN
+js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
+ ptrdiff_t offset)
+{
+ intN index;
+
+ index = js_NewSrcNote(cx, cg, type);
+ if (index >= 0) {
+ if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset))
+ return -1;
+ }
+ return index;
+}
+
+intN
+js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
+ ptrdiff_t offset1, ptrdiff_t offset2)
+{
+ intN index;
+
+ index = js_NewSrcNote(cx, cg, type);
+ if (index >= 0) {
+ if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset1))
+ return -1;
+ if (!js_SetSrcNoteOffset(cx, cg, index, 1, offset2))
+ return -1;
+ }
+ return index;
+}
+
+static JSBool
+GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg)
+{
+ JSArenaPool *pool;
+ size_t size;
+
+ /* Grow by doubling note array size; update noteMask on success. */
+ pool = cg->notePool;
+ size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1);
+ JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size);
+ if (!CG_NOTES(cg)) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1;
+ return JS_TRUE;
+}
+
+jssrcnote *
+js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn,
+ ptrdiff_t delta)
+{
+ ptrdiff_t base, limit, newdelta, diff;
+ intN index;
+
+ /*
+ * Called only from OptimizeSpanDeps and js_FinishTakingSrcNotes to add to
+ * main script note deltas, and only by a small positive amount.
+ */
+ JS_ASSERT(cg->current == &cg->main);
+ JS_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT);
+
+ base = SN_DELTA(sn);
+ limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
+ newdelta = base + delta;
+ if (newdelta < limit) {
+ SN_SET_DELTA(sn, newdelta);
+ } else {
+ index = sn - cg->main.notes;
+ if ((cg->main.noteCount & cg->main.noteMask) == 0) {
+ if (!GrowSrcNotes(cx, cg))
+ return NULL;
+ sn = cg->main.notes + index;
+ }
+ diff = cg->main.noteCount - index;
+ cg->main.noteCount++;
+ memmove(sn + 1, sn, SRCNOTE_SIZE(diff));
+ SN_MAKE_XDELTA(sn, delta);
+ sn++;
+ }
+ return sn;
+}
+
+uintN
+js_SrcNoteLength(jssrcnote *sn)
+{
+ uintN arity;
+ jssrcnote *base;
+
+ arity = (intN)js_SrcNoteSpec[SN_TYPE(sn)].arity;
+ for (base = sn++; arity; sn++, arity--) {
+ if (*sn & SN_3BYTE_OFFSET_FLAG)
+ sn += 2;
+ }
+ return sn - base;
+}
+
+JS_FRIEND_API(ptrdiff_t)
+js_GetSrcNoteOffset(jssrcnote *sn, uintN which)
+{
+ /* Find the offset numbered which (i.e., skip exactly which offsets). */
+ JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
+ JS_ASSERT(which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
+ for (sn++; which; sn++, which--) {
+ if (*sn & SN_3BYTE_OFFSET_FLAG)
+ sn += 2;
+ }
+ if (*sn & SN_3BYTE_OFFSET_FLAG) {
+ return (ptrdiff_t)(((uint32)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16)
+ | (sn[1] << 8)
+ | sn[2]);
+ }
+ return (ptrdiff_t)*sn;
+}
+
+JSBool
+js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
+ uintN which, ptrdiff_t offset)
+{
+ jssrcnote *sn;
+ ptrdiff_t diff;
+
+ if ((jsuword)offset >= (jsuword)((ptrdiff_t)SN_3BYTE_OFFSET_FLAG << 16)) {
+ ReportStatementTooLarge(cx, cg);
+ return JS_FALSE;
+ }
+
+ /* Find the offset numbered which (i.e., skip exactly which offsets). */
+ sn = &CG_NOTES(cg)[index];
+ JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
+ JS_ASSERT(which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
+ for (sn++; which; sn++, which--) {
+ if (*sn & SN_3BYTE_OFFSET_FLAG)
+ sn += 2;
+ }
+
+ /* See if the new offset requires three bytes. */
+ if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK) {
+ /* Maybe this offset was already set to a three-byte value. */
+ if (!(*sn & SN_3BYTE_OFFSET_FLAG)) {
+ /* Losing, need to insert another two bytes for this offset. */
+ index = PTRDIFF(sn, CG_NOTES(cg), jssrcnote);
+
+ /*
+ * Simultaneously test to see if the source note array must grow to
+ * accomodate either the first or second byte of additional storage
+ * required by this 3-byte offset.
+ */
+ if (((CG_NOTE_COUNT(cg) + 1) & CG_NOTE_MASK(cg)) <= 1) {
+ if (!GrowSrcNotes(cx, cg))
+ return JS_FALSE;
+ sn = CG_NOTES(cg) + index;
+ }
+ CG_NOTE_COUNT(cg) += 2;
+
+ diff = CG_NOTE_COUNT(cg) - (index + 3);
+ JS_ASSERT(diff >= 0);
+ if (diff > 0)
+ memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff));
+ }
+ *sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16));
+ *sn++ = (jssrcnote)(offset >> 8);
+ }
+ *sn = (jssrcnote)offset;
+ return JS_TRUE;
+}
+
+#ifdef DEBUG_brendan
+#define NBINS 10
+static uint32 hist[NBINS];
+
+void DumpSrcNoteSizeHist()
+{
+ static FILE *fp;
+ int i, n;
+
+ if (!fp) {
+ fp = fopen("/tmp/srcnotes.hist", "w");
+ if (!fp)
+ return;
+ setlinebuf(fp);
+ }
+ fprintf(fp, "SrcNote size histogram:\n");
+ for (i = 0; i < NBINS; i++) {
+ fprintf(fp, "%4u %4u ", JS_BIT(i), hist[i]);
+ for (n = (int) JS_HOWMANY(hist[i], 10); n > 0; --n)
+ fputc('*', fp);
+ fputc('\n', fp);
+ }
+ fputc('\n', fp);
+}
+#endif
+
+/*
+ * Fill in the storage at notes with prolog and main srcnotes; the space at
+ * notes was allocated using the CG_COUNT_FINAL_SRCNOTES macro from jsemit.h.
+ * SO DON'T CHANGE THIS FUNCTION WITHOUT AT LEAST CHECKING WHETHER jsemit.h's
+ * CG_COUNT_FINAL_SRCNOTES MACRO NEEDS CORRESPONDING CHANGES!
+ */
+JSBool
+js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes)
+{
+ uintN prologCount, mainCount, totalCount;
+ ptrdiff_t offset, delta;
+ jssrcnote *sn;
+
+ JS_ASSERT(cg->current == &cg->main);
+
+ prologCount = cg->prolog.noteCount;
+ if (prologCount && cg->prolog.currentLine != cg->firstLine) {
+ CG_SWITCH_TO_PROLOG(cg);
+ if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)cg->firstLine) < 0)
+ return JS_FALSE;
+ prologCount = cg->prolog.noteCount;
+ CG_SWITCH_TO_MAIN(cg);
+ } else {
+ /*
+ * Either no prolog srcnotes, or no line number change over prolog.
+ * We don't need a SRC_SETLINE, but we may need to adjust the offset
+ * of the first main note, by adding to its delta and possibly even
+ * prepending SRC_XDELTA notes to it to account for prolog bytecodes
+ * that came at and after the last annotated bytecode.
+ */
+ offset = CG_PROLOG_OFFSET(cg) - cg->prolog.lastNoteOffset;
+ JS_ASSERT(offset >= 0);
+ if (offset > 0) {
+ /* NB: Use as much of the first main note's delta as we can. */
+ sn = cg->main.notes;
+ delta = SN_IS_XDELTA(sn)
+ ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
+ : SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
+ if (offset < delta)
+ delta = offset;
+ for (;;) {
+ if (!js_AddToSrcNoteDelta(cx, cg, sn, delta))
+ return JS_FALSE;
+ offset -= delta;
+ if (offset == 0)
+ break;
+ delta = JS_MIN(offset, SN_XDELTA_MASK);
+ sn = cg->main.notes;
+ }
+ }
+ }
+
+ mainCount = cg->main.noteCount;
+ totalCount = prologCount + mainCount;
+ if (prologCount)
+ memcpy(notes, cg->prolog.notes, SRCNOTE_SIZE(prologCount));
+ memcpy(notes + prologCount, cg->main.notes, SRCNOTE_SIZE(mainCount));
+ SN_MAKE_TERMINATOR(&notes[totalCount]);
+
+#ifdef DEBUG_brendan
+ { int bin = JS_CeilingLog2(totalCount);
+ if (bin >= NBINS)
+ bin = NBINS - 1;
+ ++hist[bin];
+ }
+#endif
+ return JS_TRUE;
+}
+
+JSBool
+js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg)
+{
+ size_t size, incr;
+ ptrdiff_t delta;
+
+ size = TRYNOTE_SIZE(cg->treeContext.tryCount);
+ if (size <= cg->tryNoteSpace)
+ return JS_TRUE;
+
+ /*
+ * Allocate trynotes from cx->tempPool.
+ * XXX Too much growing and we bloat, as other tempPool allocators block
+ * in-place growth, and we never recycle old free space in an arena.
+ * YYY But once we consume an entire arena, we'll realloc it, letting the
+ * malloc heap recycle old space, while still freeing _en masse_ via the
+ * arena pool.
+ */
+ if (!cg->tryBase) {
+ size = JS_ROUNDUP(size, TRYNOTE_SIZE(TRYNOTE_CHUNK));
+ JS_ARENA_ALLOCATE_CAST(cg->tryBase, JSTryNote *, &cx->tempPool, size);
+ if (!cg->tryBase)
+ return JS_FALSE;
+ cg->tryNoteSpace = size;
+ cg->tryNext = cg->tryBase;
+ } else {
+ delta = PTRDIFF((char *)cg->tryNext, (char *)cg->tryBase, char);
+ incr = size - cg->tryNoteSpace;
+ incr = JS_ROUNDUP(incr, TRYNOTE_SIZE(TRYNOTE_CHUNK));
+ size = cg->tryNoteSpace;
+ JS_ARENA_GROW_CAST(cg->tryBase, JSTryNote *, &cx->tempPool, size, incr);
+ if (!cg->tryBase)
+ return JS_FALSE;
+ cg->tryNoteSpace = size + incr;
+ cg->tryNext = (JSTryNote *)((char *)cg->tryBase + delta);
+ }
+ return JS_TRUE;
+}
+
+JSTryNote *
+js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
+ ptrdiff_t end, ptrdiff_t catchStart)
+{
+ JSTryNote *tn;
+
+ JS_ASSERT(cg->tryBase <= cg->tryNext);
+ JS_ASSERT(catchStart >= 0);
+ tn = cg->tryNext++;
+ tn->start = start;
+ tn->length = end - start;
+ tn->catchStart = catchStart;
+ return tn;
+}
+
+void
+js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote *notes)
+{
+ uintN count;
+
+ count = PTRDIFF(cg->tryNext, cg->tryBase, JSTryNote);
+ if (!count)
+ return;
+
+ memcpy(notes, cg->tryBase, TRYNOTE_SIZE(count));
+ notes[count].start = 0;
+ notes[count].length = CG_OFFSET(cg);
+ notes[count].catchStart = 0;
+}
diff --git a/src/dom/js/jsemit.h b/src/dom/js/jsemit.h
new file mode 100644
index 000000000..43b520c6e
--- /dev/null
+++ b/src/dom/js/jsemit.h
@@ -0,0 +1,547 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsemit_h___
+#define jsemit_h___
+/*
+ * JS bytecode generation.
+ */
+
+#include "jsstddef.h"
+#include "jstypes.h"
+#include "jsatom.h"
+#include "jsopcode.h"
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * NB: If you add non-loop STMT_* enumerators, do so before STMT_DO_LOOP or
+ * you will break the STMT_IS_LOOP macro, just below this enum.
+ */
+typedef enum JSStmtType {
+ STMT_BLOCK = 0, /* compound statement: { s1[;... sN] } */
+ STMT_LABEL = 1, /* labeled statement: L: s */
+ STMT_IF = 2, /* if (then) statement */
+ STMT_ELSE = 3, /* else clause of if statement */
+ STMT_SWITCH = 4, /* switch statement */
+ STMT_WITH = 5, /* with statement */
+ STMT_TRY = 6, /* try statement */
+ STMT_CATCH = 7, /* catch block */
+ STMT_FINALLY = 8, /* finally statement */
+ STMT_SUBROUTINE = 9, /* gosub-target subroutine body */
+ STMT_DO_LOOP = 10, /* do/while loop statement */
+ STMT_FOR_LOOP = 11, /* for loop statement */
+ STMT_FOR_IN_LOOP = 12, /* for/in loop statement */
+ STMT_WHILE_LOOP = 13 /* while loop statement */
+} JSStmtType;
+
+#define STMT_IS_LOOP(stmt) ((stmt)->type >= STMT_DO_LOOP)
+
+typedef struct JSStmtInfo JSStmtInfo;
+
+struct JSStmtInfo {
+ JSStmtType type; /* statement type */
+ ptrdiff_t update; /* loop update offset (top if none) */
+ ptrdiff_t breaks; /* offset of last break in loop */
+ ptrdiff_t continues; /* offset of last continue in loop */
+ ptrdiff_t gosub; /* offset of last GOSUB for this finally */
+ ptrdiff_t catchJump; /* offset of last end-of-catch jump */
+ JSAtom *label; /* name of LABEL or CATCH var */
+ JSStmtInfo *down; /* info for enclosing statement */
+};
+
+#define SET_STATEMENT_TOP(stmt, top) \
+ ((stmt)->update = (top), (stmt)->breaks = \
+ (stmt)->continues = (stmt)->catchJump = (stmt)->gosub = (-1))
+
+struct JSTreeContext { /* tree context for semantic checks */
+ uint32 flags; /* statement state flags, see below */
+ uint32 tryCount; /* total count of try statements parsed */
+ JSStmtInfo *topStmt; /* top of statement info stack */
+ JSAtomList decls; /* function, const, and var declarations */
+ JSParseNode *nodeList; /* list of recyclable parse-node structs */
+};
+
+#define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */
+#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
+#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
+#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
+#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
+#define TCF_FUN_CLOSURE_VS_VAR 0x20 /* function and var with same name */
+#define TCF_FUN_USES_NONLOCALS 0x40 /* function refers to non-local names */
+#define TCF_FUN_HEAVYWEIGHT 0x80 /* function needs Call object per call */
+#define TCF_FUN_FLAGS 0xE0 /* flags to propagate from FunctionBody */
+
+#define TREE_CONTEXT_INIT(tc) \
+ ((tc)->flags = 0, (tc)->tryCount = 0, (tc)->topStmt = NULL, \
+ ATOM_LIST_INIT(&(tc)->decls), (tc)->nodeList = NULL)
+
+#define TREE_CONTEXT_FINISH(tc) \
+ ((void)0)
+
+/*
+ * Span-dependent instructions are jumps whose span (from the jump bytecode to
+ * the jump target) may require 2 or 4 bytes of immediate operand.
+ */
+typedef struct JSSpanDep JSSpanDep;
+typedef struct JSJumpTarget JSJumpTarget;
+
+struct JSSpanDep {
+ ptrdiff_t top; /* offset of first bytecode in an opcode */
+ ptrdiff_t offset; /* offset - 1 within opcode of jump operand */
+ ptrdiff_t before; /* original offset - 1 of jump operand */
+ JSJumpTarget *target; /* tagged target pointer or backpatch delta */
+};
+
+/*
+ * Jump targets are stored in an AVL tree, for O(log(n)) lookup with targets
+ * sorted by offset from left to right, so that targets after a span-dependent
+ * instruction whose jump offset operand must be extended can be found quickly
+ * and adjusted upward (toward higher offsets).
+ */
+struct JSJumpTarget {
+ ptrdiff_t offset; /* offset of span-dependent jump target */
+ int balance; /* AVL tree balance number */
+ JSJumpTarget *kids[2]; /* left and right AVL tree child pointers */
+};
+
+#define JT_LEFT 0
+#define JT_RIGHT 1
+#define JT_OTHER_DIR(dir) (1 - (dir))
+#define JT_IMBALANCE(dir) (((dir) << 1) - 1)
+#define JT_DIR(imbalance) (((imbalance) + 1) >> 1)
+
+/*
+ * Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear,
+ * so we can maintain backpatch chains when using span dependency records to
+ * hold jump offsets that overflow 16 bits.
+ */
+#define JT_TAG_BIT ((jsword) 1)
+#define JT_UNTAG_SHIFT 1
+#define JT_SET_TAG(jt) ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT))
+#define JT_CLR_TAG(jt) ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT))
+#define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT)
+
+#define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE)
+#define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT)
+#define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1)
+#define BPDELTA_TO_JT(bp) ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT))
+#define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT))
+
+#define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt))
+#define SD_SET_BPDELTA(sd,bp) ((sd)->target = BPDELTA_TO_JT(bp))
+#define SD_GET_BPDELTA(sd) (JS_ASSERT(!JT_HAS_TAG((sd)->target)), \
+ JT_TO_BPDELTA((sd)->target))
+#define SD_TARGET_OFFSET(sd) (JS_ASSERT(JT_HAS_TAG((sd)->target)), \
+ JT_CLR_TAG((sd)->target)->offset)
+
+struct JSCodeGenerator {
+ JSTreeContext treeContext; /* base state: statement info stack, etc. */
+ JSArenaPool *codePool; /* pointer to thread code arena pool */
+ JSArenaPool *notePool; /* pointer to thread srcnote arena pool */
+ void *codeMark; /* low watermark in cg->codePool */
+ void *noteMark; /* low watermark in cg->notePool */
+ void *tempMark; /* low watermark in cx->tempPool */
+ struct {
+ jsbytecode *base; /* base of JS bytecode vector */
+ jsbytecode *limit; /* one byte beyond end of bytecode */
+ jsbytecode *next; /* pointer to next free bytecode */
+ jssrcnote *notes; /* source notes, see below */
+ uintN noteCount; /* number of source notes so far */
+ uintN noteMask; /* growth increment for notes */
+ ptrdiff_t lastNoteOffset; /* code offset for last source note */
+ uintN currentLine; /* line number for tree-based srcnote gen */
+ } prolog, main, *current;
+ const char *filename; /* null or weak link to source filename */
+ uintN firstLine; /* first line, for js_NewScriptFromCG */
+ JSPrincipals *principals; /* principals for constant folding eval */
+ JSAtomList atomList; /* literals indexed for mapping */
+ intN stackDepth; /* current stack depth in script frame */
+ uintN maxStackDepth; /* maximum stack depth so far */
+ JSTryNote *tryBase; /* first exception handling note */
+ JSTryNote *tryNext; /* next available note */
+ size_t tryNoteSpace; /* # of bytes allocated at tryBase */
+ JSSpanDep *spanDeps; /* span dependent instruction records */
+ JSJumpTarget *jumpTargets; /* AVL tree of jump target offsets */
+ JSJumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */
+ uintN numSpanDeps; /* number of span dependencies */
+ uintN numJumpTargets; /* number of jump targets */
+ uintN emitLevel; /* js_EmitTree recursion level */
+};
+
+#define CG_BASE(cg) ((cg)->current->base)
+#define CG_LIMIT(cg) ((cg)->current->limit)
+#define CG_NEXT(cg) ((cg)->current->next)
+#define CG_CODE(cg,offset) (CG_BASE(cg) + (offset))
+#define CG_OFFSET(cg) PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode)
+
+#define CG_NOTES(cg) ((cg)->current->notes)
+#define CG_NOTE_COUNT(cg) ((cg)->current->noteCount)
+#define CG_NOTE_MASK(cg) ((cg)->current->noteMask)
+#define CG_LAST_NOTE_OFFSET(cg) ((cg)->current->lastNoteOffset)
+#define CG_CURRENT_LINE(cg) ((cg)->current->currentLine)
+
+#define CG_PROLOG_BASE(cg) ((cg)->prolog.base)
+#define CG_PROLOG_LIMIT(cg) ((cg)->prolog.limit)
+#define CG_PROLOG_NEXT(cg) ((cg)->prolog.next)
+#define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff))
+#define CG_PROLOG_OFFSET(cg) PTRDIFF(CG_PROLOG_NEXT(cg), CG_PROLOG_BASE(cg),\
+ jsbytecode)
+
+#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main)
+#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
+
+/*
+ * Initialize cg to allocate bytecode space from codePool, source note space
+ * from notePool, and all other arena-allocated temporaries from cx->tempPool.
+ * Return true on success. Report an error and return false if the initial
+ * code segment can't be allocated.
+ */
+extern JS_FRIEND_API(JSBool)
+js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
+ JSArenaPool *codePool, JSArenaPool *notePool,
+ const char *filename, uintN lineno,
+ JSPrincipals *principals);
+
+/*
+ * Release cg->codePool, cg->notePool, and cx->tempPool to marks set by
+ * js_InitCodeGenerator. Note that cgs are magic: they own the arena pool
+ * "tops-of-stack" space above their codeMark, noteMark, and tempMark points.
+ * This means you cannot alloc from tempPool and save the pointer beyond the
+ * next JS_FinishCodeGenerator.
+ */
+extern JS_FRIEND_API(void)
+js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg);
+
+/*
+ * Emit one bytecode.
+ */
+extern ptrdiff_t
+js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op);
+
+/*
+ * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1).
+ */
+extern ptrdiff_t
+js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1);
+
+/*
+ * Emit three bytecodes, an opcode with two bytes of immediate operands.
+ */
+extern ptrdiff_t
+js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
+ jsbytecode op2);
+
+/*
+ * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
+ */
+extern ptrdiff_t
+js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra);
+
+/*
+ * Unsafe macro to call js_SetJumpOffset and return false if it does.
+ */
+#define CHECK_AND_SET_JUMP_OFFSET(cx,cg,pc,off) \
+ JS_BEGIN_MACRO \
+ if (!js_SetJumpOffset(cx, cg, pc, off)) \
+ return JS_FALSE; \
+ JS_END_MACRO
+
+#define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off) \
+ CHECK_AND_SET_JUMP_OFFSET(cx, cg, CG_CODE(cg,off), CG_OFFSET(cg) - (off))
+
+extern JSBool
+js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
+ ptrdiff_t off);
+
+/* Test whether we're in a with statement. */
+extern JSBool
+js_InWithStatement(JSTreeContext *tc);
+
+/* Test whether we're in a catch block with exception named by atom. */
+extern JSBool
+js_InCatchBlock(JSTreeContext *tc, JSAtom *atom);
+
+/*
+ * Push the C-stack-allocated struct at stmt onto the stmtInfo stack.
+ */
+extern void
+js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
+ ptrdiff_t top);
+
+/*
+ * Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it
+ * is up to the caller to free it.
+ */
+extern void
+js_PopStatement(JSTreeContext *tc);
+
+/*
+ * Like js_PopStatement(&cg->treeContext), also patch breaks and continues.
+ * May fail if a jump offset overflows.
+ */
+extern JSBool
+js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg);
+
+/*
+ * Emit code into cg for the tree rooted at pn.
+ */
+extern JSBool
+js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn);
+
+/*
+ * Emit code into cg for the tree rooted at body, then create a persistent
+ * script for fun from cg.
+ */
+extern JSBool
+js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
+ JSFunction *fun);
+
+/*
+ * Source notes generated along with bytecode for decompiling and debugging.
+ * A source note is a uint8 with 5 bits of type and 3 of offset from the pc of
+ * the previous note. If 3 bits of offset aren't enough, extended delta notes
+ * (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits
+ * are emitted before the next note. Some notes have operand offsets encoded
+ * immediately after them, in note bytes or byte-triples.
+ *
+ * Source Note Extended Delta
+ * +7-6-5-4-3+2-1-0+ +7-6-5+4-3-2-1-0+
+ * |note-type|delta| |1 1| ext-delta |
+ * +---------+-----+ +---+-----------+
+ *
+ * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE,
+ * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
+ *
+ * NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its
+ * initializers need to match the order here.
+ */
+typedef enum JSSrcNoteType {
+ SRC_NULL = 0, /* terminates a note vector */
+ SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */
+ SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */
+ SRC_WHILE = 3, /* JSOP_IFEQ is from a while loop */
+ SRC_FOR = 4, /* JSOP_NOP or JSOP_POP in for loop head */
+ SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break;
+ also used on JSOP_ENDINIT if extra comma
+ at end of array literal: [1,2,,] */
+ SRC_VAR = 6, /* JSOP_NAME/SETNAME/FORNAME in a var decl */
+ SRC_PCDELTA = 7, /* offset from comma-operator to next POP,
+ or from CONDSWITCH to first CASE opcode */
+ SRC_ASSIGNOP = 8, /* += or another assign-op follows */
+ SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */
+ SRC_RESERVED0 = 10, /* reserved for future use */
+ SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */
+ SRC_PCBASE = 12, /* offset of first obj.prop.subprop bytecode */
+ SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */
+ SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */
+ SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */
+ SRC_BREAK2LABEL = 16, /* JSOP_GOTO for 'break label' with atomid */
+ SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */
+ SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch,
+ 2nd off to first JSOP_CASE if condswitch */
+ SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */
+ SRC_CATCH = 20, /* catch block has guard */
+ SRC_CONST = 21, /* JSOP_SETCONST in a const decl */
+ SRC_NEWLINE = 22, /* bytecode follows a source newline */
+ SRC_SETLINE = 23, /* a file-absolute source line number note */
+ SRC_XDELTA = 24 /* 24-31 are for extended delta notes */
+} JSSrcNoteType;
+
+#define SN_TYPE_BITS 5
+#define SN_DELTA_BITS 3
+#define SN_XDELTA_BITS 6
+#define SN_TYPE_MASK (JS_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS)
+#define SN_DELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_DELTA_BITS))
+#define SN_XDELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_XDELTA_BITS))
+
+#define SN_MAKE_NOTE(sn,t,d) (*(sn) = (jssrcnote) \
+ (((t) << SN_DELTA_BITS) \
+ | ((d) & SN_DELTA_MASK)))
+#define SN_MAKE_XDELTA(sn,d) (*(sn) = (jssrcnote) \
+ ((SRC_XDELTA << SN_DELTA_BITS) \
+ | ((d) & SN_XDELTA_MASK)))
+
+#define SN_IS_XDELTA(sn) ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA)
+#define SN_TYPE(sn) (SN_IS_XDELTA(sn) ? SRC_XDELTA \
+ : *(sn) >> SN_DELTA_BITS)
+#define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn))
+#define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE)
+
+#define SN_DELTA(sn) ((ptrdiff_t)(SN_IS_XDELTA(sn) \
+ ? *(sn) & SN_XDELTA_MASK \
+ : *(sn) & SN_DELTA_MASK))
+#define SN_SET_DELTA(sn,delta) (SN_IS_XDELTA(sn) \
+ ? SN_MAKE_XDELTA(sn, delta) \
+ : SN_MAKE_NOTE(sn, SN_TYPE(sn), delta))
+
+#define SN_DELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_DELTA_BITS))
+#define SN_XDELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_XDELTA_BITS))
+
+/*
+ * Offset fields follow certain notes and are frequency-encoded: an offset in
+ * [0,0x7f] consumes one byte, an offset in [0x80,0x7fffff] takes three, and
+ * the high bit of the first byte is set.
+ */
+#define SN_3BYTE_OFFSET_FLAG 0x80
+#define SN_3BYTE_OFFSET_MASK 0x7f
+
+typedef struct JSSrcNoteSpec {
+ const char *name; /* name for disassembly/debugging output */
+ uint8 arity; /* number of offset operands */
+ uint8 offsetBias; /* bias of offset(s) from annotated pc */
+ int8 isSpanDep; /* 1 or -1 if offsets could span extended ops,
+ 0 otherwise; sign tells span direction */
+} JSSrcNoteSpec;
+
+extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[];
+extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn);
+
+#define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \
+ : js_SrcNoteLength(sn))
+#define SN_NEXT(sn) ((sn) + SN_LENGTH(sn))
+
+/* A source note array is terminated by an all-zero element. */
+#define SN_MAKE_TERMINATOR(sn) (*(sn) = SRC_NULL)
+#define SN_IS_TERMINATOR(sn) (*(sn) == SRC_NULL)
+
+/*
+ * Append a new source note of the given type (and therefore size) to cg's
+ * notes dynamic array, updating cg->noteCount. Return the new note's index
+ * within the array pointed at by cg->current->notes. Return -1 if out of
+ * memory.
+ */
+extern intN
+js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type);
+
+extern intN
+js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
+ ptrdiff_t offset);
+
+extern intN
+js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
+ ptrdiff_t offset1, ptrdiff_t offset2);
+
+/*
+ * NB: this function can add at most one extra extended delta note.
+ */
+extern jssrcnote *
+js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn,
+ ptrdiff_t delta);
+
+/*
+ * Get and set the offset operand identified by which (0 for the first, etc.).
+ */
+extern JS_FRIEND_API(ptrdiff_t)
+js_GetSrcNoteOffset(jssrcnote *sn, uintN which);
+
+extern JSBool
+js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
+ uintN which, ptrdiff_t offset);
+
+/*
+ * Finish taking source notes in cx's notePool, copying final notes to the new
+ * stable store allocated by the caller and passed in via notes. Return false
+ * on malloc failure, which means this function reported an error.
+ *
+ * To compute the number of jssrcnotes to allocate and pass in via notes, use
+ * the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of
+ * js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes
+ * FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES!
+ */
+#define CG_COUNT_FINAL_SRCNOTES(cg, cnt) \
+ JS_BEGIN_MACRO \
+ ptrdiff_t diff_ = CG_PROLOG_OFFSET(cg) - (cg)->prolog.lastNoteOffset; \
+ cnt = (cg)->prolog.noteCount + (cg)->main.noteCount + 1; \
+ if ((cg)->prolog.noteCount && \
+ (cg)->prolog.currentLine != (cg)->firstLine) { \
+ if (diff_ > SN_DELTA_MASK) \
+ cnt += JS_HOWMANY(diff_ - SN_DELTA_MASK, SN_XDELTA_MASK); \
+ cnt += 2 + (((cg)->firstLine > SN_3BYTE_OFFSET_MASK) << 1); \
+ } else if (diff_ > 0) { \
+ if (cg->main.noteCount) { \
+ jssrcnote *sn_ = (cg)->main.notes; \
+ diff_ -= SN_IS_XDELTA(sn_) \
+ ? SN_XDELTA_MASK - (*sn_ & SN_XDELTA_MASK) \
+ : SN_DELTA_MASK - (*sn_ & SN_DELTA_MASK); \
+ } \
+ if (diff_ > 0) \
+ cnt += JS_HOWMANY(diff_, SN_XDELTA_MASK); \
+ } \
+ JS_END_MACRO
+
+extern JSBool
+js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes);
+
+/*
+ * Allocate cg->treeContext.tryCount notes (plus one for the end sentinel)
+ * from cx->tempPool and set up cg->tryBase/tryNext for exactly tryCount
+ * js_NewTryNote calls. The storage is freed by js_FinishCodeGenerator.
+ */
+extern JSBool
+js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg);
+
+/*
+ * Grab the next trynote slot in cg, filling it in appropriately.
+ */
+extern JSTryNote *
+js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
+ ptrdiff_t end, ptrdiff_t catchStart);
+
+/*
+ * Finish generating exception information into the space at notes. As with
+ * js_FinishTakingSrcNotes, the caller must use CG_COUNT_FINAL_TRYNOTES(cg) to
+ * preallocate enough space in a JSTryNote[] to pass as the notes parameter of
+ * js_FinishTakingTryNotes.
+ */
+#define CG_COUNT_FINAL_TRYNOTES(cg, cnt) \
+ JS_BEGIN_MACRO \
+ cnt = ((cg)->tryNext > (cg)->tryBase) \
+ ? PTRDIFF(cg->tryNext, cg->tryBase, JSTryNote) + 1 \
+ : 0; \
+ JS_END_MACRO
+
+extern void
+js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote *notes);
+
+JS_END_EXTERN_C
+
+#endif /* jsemit_h___ */
diff --git a/src/dom/js/jsexn.c b/src/dom/js/jsexn.c
new file mode 100644
index 000000000..c407c1628
--- /dev/null
+++ b/src/dom/js/jsexn.c
@@ -0,0 +1,1081 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS standard exception implementation.
+ */
+
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsbit.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsexn.h"
+#include "jsfun.h"
+#include "jsinterp.h"
+#include "jsopcode.h"
+#include "jsnum.h"
+#include "jsscript.h"
+
+#if JS_HAS_ERROR_EXCEPTIONS
+#if !JS_HAS_EXCEPTIONS
+# error "JS_HAS_EXCEPTIONS must be defined to use JS_HAS_ERROR_EXCEPTIONS"
+#endif
+
+/* XXX consider adding rt->atomState.messageAtom */
+static char js_message_str[] = "message";
+static char js_filename_str[] = "fileName";
+static char js_lineno_str[] = "lineNumber";
+static char js_stack_str[] = "stack";
+
+/* Forward declarations for ExceptionClass's initializer. */
+static JSBool
+Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+static void
+exn_finalize(JSContext *cx, JSObject *obj);
+
+static JSClass ExceptionClass = {
+ "Error",
+ JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, exn_finalize,
+ NULL, NULL, NULL, Exception,
+ NULL, NULL, NULL, 0
+};
+
+/*
+ * A copy of the JSErrorReport originally generated.
+ */
+typedef struct JSExnPrivate {
+ JSErrorReport *errorReport;
+} JSExnPrivate;
+
+/*
+ * Undo all the damage done by exn_newPrivate.
+ */
+static void
+exn_destroyPrivate(JSContext *cx, JSExnPrivate *privateData)
+{
+ JSErrorReport *report;
+ const jschar **args;
+
+ if (!privateData)
+ return;
+ report = privateData->errorReport;
+ if (report) {
+ if (report->uclinebuf)
+ JS_free(cx, (void *)report->uclinebuf);
+ if (report->filename)
+ JS_free(cx, (void *)report->filename);
+ if (report->ucmessage)
+ JS_free(cx, (void *)report->ucmessage);
+ if (report->messageArgs) {
+ args = report->messageArgs;
+ while (*args != NULL)
+ JS_free(cx, (void *)*args++);
+ JS_free(cx, (void *)report->messageArgs);
+ }
+ JS_free(cx, report);
+ }
+ JS_free(cx, privateData);
+}
+
+/*
+ * Copy everything interesting about an error into allocated memory.
+ */
+static JSExnPrivate *
+exn_newPrivate(JSContext *cx, JSErrorReport *report)
+{
+ intN i;
+ JSExnPrivate *newPrivate;
+ JSErrorReport *newReport;
+ size_t capacity;
+
+ newPrivate = (JSExnPrivate *)JS_malloc(cx, sizeof (JSExnPrivate));
+ if (!newPrivate)
+ return NULL;
+ memset(newPrivate, 0, sizeof (JSExnPrivate));
+
+ /* Copy the error report */
+ newReport = (JSErrorReport *)JS_malloc(cx, sizeof (JSErrorReport));
+ if (!newReport)
+ goto error;
+ memset(newReport, 0, sizeof (JSErrorReport));
+ newPrivate->errorReport = newReport;
+
+ if (report->filename != NULL) {
+ newReport->filename = JS_strdup(cx, report->filename);
+ if (!newReport->filename)
+ goto error;
+ } else {
+ newReport->filename = NULL;
+ }
+
+ newReport->lineno = report->lineno;
+
+ /*
+ * We don't need to copy linebuf and tokenptr, because they
+ * point into the deflated string cache. (currently?)
+ */
+ newReport->linebuf = report->linebuf;
+ newReport->tokenptr = report->tokenptr;
+
+ /*
+ * But we do need to copy uclinebuf, uctokenptr, because they're
+ * pointers into internal tokenstream structs, and may go away.
+ */
+ if (report->uclinebuf != NULL) {
+ capacity = js_strlen(report->uclinebuf) + 1;
+ newReport->uclinebuf =
+ (const jschar *)JS_malloc(cx, capacity * sizeof(jschar));
+ if (!newReport->uclinebuf)
+ goto error;
+ js_strncpy((jschar *)newReport->uclinebuf, report->uclinebuf, capacity);
+ newReport->uctokenptr = newReport->uclinebuf + (report->uctokenptr -
+ report->uclinebuf);
+ } else {
+ newReport->uclinebuf = newReport->uctokenptr = NULL;
+ }
+
+ if (report->ucmessage != NULL) {
+ capacity = js_strlen(report->ucmessage) + 1;
+ newReport->ucmessage = (const jschar *)
+ JS_malloc(cx, capacity * sizeof(jschar));
+ if (!newReport->ucmessage)
+ goto error;
+ js_strncpy((jschar *)newReport->ucmessage, report->ucmessage, capacity);
+
+ if (report->messageArgs) {
+ for (i = 0; report->messageArgs[i] != NULL; i++)
+ continue;
+ JS_ASSERT(i);
+ newReport->messageArgs =
+ (const jschar **)JS_malloc(cx, (i + 1) * sizeof(jschar *));
+ if (!newReport->messageArgs)
+ goto error;
+ for (i = 0; report->messageArgs[i] != NULL; i++) {
+ capacity = js_strlen(report->messageArgs[i]) + 1;
+ newReport->messageArgs[i] =
+ (const jschar *)JS_malloc(cx, capacity * sizeof(jschar));
+ if (!newReport->messageArgs[i])
+ goto error;
+ js_strncpy((jschar *)(newReport->messageArgs[i]),
+ report->messageArgs[i], capacity);
+ }
+ newReport->messageArgs[i] = NULL;
+ } else {
+ newReport->messageArgs = NULL;
+ }
+ } else {
+ newReport->ucmessage = NULL;
+ newReport->messageArgs = NULL;
+ }
+ newReport->errorNumber = report->errorNumber;
+
+ /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */
+ newReport->flags = report->flags;
+
+ return newPrivate;
+error:
+ exn_destroyPrivate(cx, newPrivate);
+ return NULL;
+}
+
+static void
+exn_finalize(JSContext *cx, JSObject *obj)
+{
+ JSExnPrivate *privateData;
+ jsval privateValue;
+
+ privateValue = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+
+ if (!JSVAL_IS_VOID(privateValue)) {
+ privateData = (JSExnPrivate*) JSVAL_TO_PRIVATE(privateValue);
+ if (privateData)
+ exn_destroyPrivate(cx, privateData);
+ }
+}
+
+JSErrorReport *
+js_ErrorFromException(JSContext *cx, jsval exn)
+{
+ JSObject *obj;
+ JSExnPrivate *privateData;
+ jsval privateValue;
+
+ if (JSVAL_IS_PRIMITIVE(exn))
+ return NULL;
+ obj = JSVAL_TO_OBJECT(exn);
+ if (OBJ_GET_CLASS(cx, obj) != &ExceptionClass)
+ return NULL;
+ privateValue = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ if (JSVAL_IS_VOID(privateValue))
+ return NULL;
+ privateData = (JSExnPrivate*) JSVAL_TO_PRIVATE(privateValue);
+ if (!privateData)
+ return NULL;
+
+ JS_ASSERT(privateData->errorReport);
+ return privateData->errorReport;
+}
+
+/*
+ * This must be kept in synch with the exceptions array below.
+ * XXX use a jsexn.tbl file a la jsopcode.tbl
+ */
+typedef enum JSExnType {
+ JSEXN_NONE = -1,
+ JSEXN_ERR,
+ JSEXN_INTERNALERR,
+ JSEXN_EVALERR,
+ JSEXN_RANGEERR,
+ JSEXN_REFERENCEERR,
+ JSEXN_SYNTAXERR,
+ JSEXN_TYPEERR,
+ JSEXN_URIERR,
+ JSEXN_LIMIT
+} JSExnType;
+
+struct JSExnSpec {
+ int protoIndex;
+ const char *name;
+ JSNative native;
+};
+
+/*
+ * All *Error constructors share the same JSClass, ExceptionClass. But each
+ * constructor function for an *Error class must have a distinct native 'call'
+ * function pointer, in order for instanceof to work properly across multiple
+ * standard class sets. See jsfun.c:fun_hasInstance.
+ */
+#define MAKE_EXCEPTION_CTOR(name) \
+const char js_##name##_str[] = #name; \
+static JSBool \
+name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
+{ \
+ return Exception(cx, obj, argc, argv, rval); \
+}
+
+MAKE_EXCEPTION_CTOR(Error)
+MAKE_EXCEPTION_CTOR(InternalError)
+MAKE_EXCEPTION_CTOR(EvalError)
+MAKE_EXCEPTION_CTOR(RangeError)
+MAKE_EXCEPTION_CTOR(ReferenceError)
+MAKE_EXCEPTION_CTOR(SyntaxError)
+MAKE_EXCEPTION_CTOR(TypeError)
+MAKE_EXCEPTION_CTOR(URIError)
+
+#undef MAKE_EXCEPTION_CTOR
+
+static struct JSExnSpec exceptions[] = {
+ { JSEXN_NONE, js_Error_str, Error },
+ { JSEXN_ERR, js_InternalError_str, InternalError },
+ { JSEXN_ERR, js_EvalError_str, EvalError },
+ { JSEXN_ERR, js_RangeError_str, RangeError },
+ { JSEXN_ERR, js_ReferenceError_str, ReferenceError },
+ { JSEXN_ERR, js_SyntaxError_str, SyntaxError },
+ { JSEXN_ERR, js_TypeError_str, TypeError },
+ { JSEXN_ERR, js_URIError_str, URIError },
+ {0,NULL,NULL}
+};
+
+static JSBool
+InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message,
+ JSString *filename, uintN lineno)
+{
+ JSCheckAccessOp checkAccess;
+ JSErrorReporter older;
+ JSExceptionState *state;
+ jschar *stackbuf;
+ size_t stacklen, stackmax;
+ JSStackFrame *fp;
+ jsval callerid, v;
+ JSBool ok;
+ JSString *argsrc, *stack;
+ uintN i, ulineno;
+ const char *cp;
+ char ulnbuf[11];
+
+ if (!JS_DefineProperty(cx, obj, js_message_str, STRING_TO_JSVAL(message),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return JS_FALSE;
+ }
+
+ if (!JS_DefineProperty(cx, obj, js_filename_str,
+ STRING_TO_JSVAL(filename),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return JS_FALSE;
+ }
+
+ if (!JS_DefineProperty(cx, obj, js_lineno_str,
+ INT_TO_JSVAL(lineno),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return JS_FALSE;
+ }
+
+ /*
+ * Set the 'stack' property.
+ *
+ * First, set aside any error reporter for cx and save its exception state
+ * so we can suppress any checkAccess failures. Such failures should stop
+ * the backtrace procedure, not result in a failure of this constructor.
+ */
+ checkAccess = cx->runtime->checkObjectAccess;
+ if (checkAccess) {
+ older = JS_SetErrorReporter(cx, NULL);
+ state = JS_SaveExceptionState(cx);
+ }
+#ifdef __GNUC__ /* suppress bogus gcc warnings */
+ else {
+ older = NULL;
+ state = NULL;
+ }
+#endif
+ callerid = ATOM_KEY(cx->runtime->atomState.callerAtom);
+
+ /*
+ * Prepare to allocate a jschar buffer at stackbuf, where stacklen indexes
+ * the next free jschar slot, and with room for at most stackmax non-null
+ * jschars. If stackbuf is non-null, it always contains an extra slot for
+ * the null terminator we'll store at the end, as a backstop.
+ *
+ * All early returns must goto done after this point, till the after-loop
+ * cleanup code has run!
+ */
+ stackbuf = NULL;
+ stacklen = stackmax = 0;
+ ok = JS_TRUE;
+
+#define APPEND_CHAR_TO_STACK(c) \
+ JS_BEGIN_MACRO \
+ if (stacklen == stackmax) { \
+ void *ptr_; \
+ stackmax = stackmax ? 2 * stackmax : 64; \
+ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \
+ if (!ptr_) { \
+ ok = JS_FALSE; \
+ goto done; \
+ } \
+ stackbuf = ptr_; \
+ } \
+ stackbuf[stacklen++] = (c); \
+ JS_END_MACRO
+
+#define APPEND_STRING_TO_STACK(str) \
+ JS_BEGIN_MACRO \
+ JSString *str_ = str; \
+ size_t length_ = JSSTRING_LENGTH(str_); \
+ if (stacklen + length_ > stackmax) { \
+ void *ptr_; \
+ stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \
+ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \
+ if (!ptr_) { \
+ ok = JS_FALSE; \
+ goto done; \
+ } \
+ stackbuf = ptr_; \
+ } \
+ js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_); \
+ stacklen += length_; \
+ JS_END_MACRO
+
+ for (fp = cx->fp; fp; fp = fp->down) {
+ if (checkAccess) {
+ v = (fp->fun && fp->argv) ? fp->argv[-2] : JSVAL_NULL;
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ ok = checkAccess(cx, fp->fun->object, callerid, JSACC_READ, &v);
+ if (!ok) {
+ ok = JS_TRUE;
+ break;
+ }
+ }
+ }
+
+ if (fp->fun) {
+ if (fp->fun->atom)
+ APPEND_STRING_TO_STACK(ATOM_TO_STRING(fp->fun->atom));
+
+ APPEND_CHAR_TO_STACK('(');
+ for (i = 0; i < fp->argc; i++) {
+ /* Avoid toSource bloat and fallibility for object types. */
+ v = fp->argv[i];
+ if (JSVAL_IS_PRIMITIVE(v)) {
+ argsrc = js_ValueToSource(cx, v);
+ } else if (JSVAL_IS_FUNCTION(cx, v)) {
+ /* XXX Avoid function decompilation bloat for now. */
+ argsrc = JS_GetFunctionId(JS_ValueToFunction(cx, v));
+ if (!argsrc)
+ argsrc = js_ValueToSource(cx, v);
+ } else {
+ /* XXX Avoid toString on objects, it takes too long and
+ uses too much memory, for too many classes (see
+ Mozilla bug 166743). */
+ char buf[100];
+ JS_snprintf(buf, sizeof buf, "[object %s]",
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v))->name);
+ argsrc = JS_NewStringCopyZ(cx, buf);
+ }
+ if (!argsrc) {
+ ok = JS_FALSE;
+ goto done;
+ }
+ if (i > 0)
+ APPEND_CHAR_TO_STACK(',');
+ APPEND_STRING_TO_STACK(argsrc);
+ }
+ APPEND_CHAR_TO_STACK(')');
+ }
+
+ APPEND_CHAR_TO_STACK('@');
+ if (fp->script && fp->script->filename) {
+ for (cp = fp->script->filename; *cp; cp++)
+ APPEND_CHAR_TO_STACK(*cp);
+ }
+ APPEND_CHAR_TO_STACK(':');
+ if (fp->script && fp->pc) {
+ ulineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+ JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", ulineno);
+ for (cp = ulnbuf; *cp; cp++)
+ APPEND_CHAR_TO_STACK(*cp);
+ } else {
+ APPEND_CHAR_TO_STACK('0');
+ }
+ APPEND_CHAR_TO_STACK('\n');
+ }
+
+#undef APPEND_CHAR_TO_STACK
+#undef APPEND_STRING_TO_STACK
+
+done:
+ if (checkAccess) {
+ if (ok)
+ JS_RestoreExceptionState(cx, state);
+ else
+ JS_DropExceptionState(cx, state);
+ JS_SetErrorReporter(cx, older);
+ }
+ if (!ok) {
+ JS_free(cx, stackbuf);
+ return JS_FALSE;
+ }
+
+ if (!stackbuf) {
+ stack = cx->runtime->emptyString;
+ } else {
+ /* NB: if stackbuf was allocated, it has room for the terminator. */
+ JS_ASSERT(stacklen <= stackmax);
+ if (stacklen < stackmax) {
+ /*
+ * Realloc can fail when shrinking on some FreeBSD versions, so
+ * don't use JS_realloc here; simply let the oversized allocation
+ * be owned by the string in that rare case.
+ */
+ void *shrunk = realloc(stackbuf, (stacklen+1) * sizeof(jschar));
+ if (shrunk)
+ stackbuf = shrunk;
+ }
+ stackbuf[stacklen] = 0;
+ stack = js_NewString(cx, stackbuf, stacklen, 0);
+ if (!stack) {
+ JS_free(cx, stackbuf);
+ return JS_FALSE;
+ }
+ }
+ return JS_DefineProperty(cx, obj, js_stack_str,
+ STRING_TO_JSVAL(stack),
+ NULL, NULL, JSPROP_ENUMERATE);
+}
+
+static JSBool
+Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSBool ok;
+ jsval pval;
+ int32 lineno;
+ JSString *message, *filename;
+
+ if (cx->creatingException)
+ return JS_FALSE;
+ cx->creatingException = JS_TRUE;
+
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ /*
+ * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
+ * called as functions, without operator new. But as we do not give
+ * each constructor a distinct JSClass, whose .name member is used by
+ * js_NewObject to find the class prototype, we must get the class
+ * prototype ourselves.
+ */
+ ok = OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(argv[-2]),
+ (jsid)cx->runtime->atomState.classPrototypeAtom,
+ &pval);
+ if (!ok)
+ goto out;
+ obj = js_NewObject(cx, &ExceptionClass, JSVAL_TO_OBJECT(pval), NULL);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ *rval = OBJECT_TO_JSVAL(obj);
+ }
+
+ /*
+ * If it's a new object of class Exception, then null out the private
+ * data so that the finalizer doesn't attempt to free it.
+ */
+ if (OBJ_GET_CLASS(cx, obj) == &ExceptionClass)
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, JSVAL_VOID);
+
+ /* Set the 'message' property. */
+ if (argc != 0) {
+ message = js_ValueToString(cx, argv[0]);
+ if (!message) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ } else {
+ message = cx->runtime->emptyString;
+ }
+
+ /* Set the 'fileName' property. */
+ if (argc > 1) {
+ filename = js_ValueToString(cx, argv[1]);
+ if (!filename) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ } else {
+ filename = cx->runtime->emptyString;
+ }
+
+ /* Set the 'lineNumber' property. */
+ if (argc > 2) {
+ ok = js_ValueToInt32(cx, argv[2], &lineno);
+ if (!ok)
+ goto out;
+ } else {
+ lineno = 0;
+ }
+
+ ok = InitExceptionObject(cx, obj, message, filename, lineno);
+
+out:
+ cx->creatingException = JS_FALSE;
+ return ok;
+}
+
+/*
+ * Convert to string.
+ *
+ * This method only uses JavaScript-modifiable properties name, message. It
+ * is left to the host to check for private data and report filename and line
+ * number information along with this message.
+ */
+static JSBool
+exn_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+ JSString *name, *message, *result;
+ jschar *chars, *cp;
+ size_t name_length, message_length, length;
+
+ if (!OBJ_GET_PROPERTY(cx, obj, (jsid)cx->runtime->atomState.nameAtom, &v))
+ return JS_FALSE;
+ name = js_ValueToString(cx, v);
+ if (!name)
+ return JS_FALSE;
+
+ if (!JS_GetProperty(cx, obj, js_message_str, &v) ||
+ !(message = js_ValueToString(cx, v))) {
+ return JS_FALSE;
+ }
+
+ if (JSSTRING_LENGTH(message) != 0) {
+ name_length = JSSTRING_LENGTH(name);
+ message_length = JSSTRING_LENGTH(message);
+ length = name_length + message_length + 2;
+ cp = chars = (jschar*) JS_malloc(cx, (length + 1) * sizeof(jschar));
+ if (!chars)
+ return JS_FALSE;
+
+ js_strncpy(cp, JSSTRING_CHARS(name), name_length);
+ cp += name_length;
+ *cp++ = ':'; *cp++ = ' ';
+ js_strncpy(cp, JSSTRING_CHARS(message), message_length);
+ cp += message_length;
+ *cp = 0;
+
+ result = js_NewString(cx, chars, length, 0);
+ if (!result) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+ } else {
+ result = name;
+ }
+
+ *rval = STRING_TO_JSVAL(result);
+ return JS_TRUE;
+}
+
+#if JS_HAS_TOSOURCE
+/*
+ * Return a string that may eval to something similar to the original object.
+ */
+static JSBool
+exn_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+ JSString *name, *message, *filename, *lineno_as_str, *result;
+ int32 lineno;
+ size_t lineno_length, name_length, message_length, filename_length, length;
+ jschar *chars, *cp;
+
+ if (!OBJ_GET_PROPERTY(cx, obj, (jsid)cx->runtime->atomState.nameAtom, &v))
+ return JS_FALSE;
+ name = js_ValueToString(cx, v);
+ if (!name)
+ return JS_FALSE;
+
+ if (!JS_GetProperty(cx, obj, js_message_str, &v) ||
+ !(message = js_ValueToSource(cx, v))) {
+ return JS_FALSE;
+ }
+
+ if (!JS_GetProperty(cx, obj, js_filename_str, &v) ||
+ !(filename = js_ValueToSource(cx, v))) {
+ return JS_FALSE;
+ }
+
+ if (!JS_GetProperty(cx, obj, js_lineno_str, &v) ||
+ !js_ValueToInt32 (cx, v, &lineno)) {
+ return JS_FALSE;
+ }
+
+ if (lineno != 0) {
+ if (!(lineno_as_str = js_ValueToString(cx, v))) {
+ return JS_FALSE;
+ }
+ lineno_length = JSSTRING_LENGTH(lineno_as_str);
+ } else {
+ lineno_as_str = NULL;
+ lineno_length = 0;
+ }
+
+ /* Magic 8, for the characters in ``(new ())''. */
+ name_length = JSSTRING_LENGTH(name);
+ message_length = JSSTRING_LENGTH(message);
+ length = 8 + name_length + message_length;
+
+ filename_length = JSSTRING_LENGTH(filename);
+ if (filename_length != 0) {
+ /* append filename as ``, {filename}'' */
+ length += 2 + filename_length;
+ if (lineno_as_str) {
+ /* append lineno as ``, {lineno_as_str}'' */
+ length += 2 + lineno_length;
+ }
+ } else {
+ if (lineno_as_str) {
+ /*
+ * no filename, but have line number,
+ * need to append ``, "", {lineno_as_str}''
+ */
+ length += 6 + lineno_length;
+ }
+ }
+
+ cp = chars = (jschar*) JS_malloc(cx, (length + 1) * sizeof(jschar));
+ if (!chars)
+ return JS_FALSE;
+
+ *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
+ js_strncpy(cp, JSSTRING_CHARS(name), name_length);
+ cp += name_length;
+ *cp++ = '(';
+ if (message_length != 0) {
+ js_strncpy(cp, JSSTRING_CHARS(message), message_length);
+ cp += message_length;
+ }
+
+ if (filename_length != 0) {
+ /* append filename as ``, {filename}'' */
+ *cp++ = ','; *cp++ = ' ';
+ js_strncpy(cp, JSSTRING_CHARS(filename), filename_length);
+ cp += filename_length;
+ } else {
+ if (lineno_as_str) {
+ /*
+ * no filename, but have line number,
+ * need to append ``, "", {lineno_as_str}''
+ */
+ *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"';
+ }
+ }
+ if (lineno_as_str) {
+ /* append lineno as ``, {lineno_as_str}'' */
+ *cp++ = ','; *cp++ = ' ';
+ js_strncpy(cp, JSSTRING_CHARS(lineno_as_str), lineno_length);
+ cp += lineno_length;
+ }
+
+ *cp++ = ')'; *cp++ = ')'; *cp = 0;
+
+ result = js_NewString(cx, chars, length, 0);
+ if (!result) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(result);
+ return JS_TRUE;
+}
+#endif
+
+static JSFunctionSpec exception_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, exn_toSource, 0,0,0},
+#endif
+ {js_toString_str, exn_toString, 0,0,0},
+ {0,0,0,0,0}
+};
+
+JSObject *
+js_InitExceptionClasses(JSContext *cx, JSObject *obj)
+{
+ int i;
+ JSObject *protos[JSEXN_LIMIT];
+
+ /* Initialize the prototypes first. */
+ for (i = 0; exceptions[i].name != 0; i++) {
+ JSAtom *atom;
+ JSFunction *fun;
+ JSString *nameString;
+ int protoIndex = exceptions[i].protoIndex;
+
+ /* Make the prototype for the current constructor name. */
+ protos[i] = js_NewObject(cx, &ExceptionClass,
+ (protoIndex != JSEXN_NONE)
+ ? protos[protoIndex]
+ : NULL,
+ obj);
+ if (!protos[i])
+ return NULL;
+
+ /* So exn_finalize knows whether to destroy private data. */
+ OBJ_SET_SLOT(cx, protos[i], JSSLOT_PRIVATE, JSVAL_VOID);
+
+ atom = js_Atomize(cx, exceptions[i].name, strlen(exceptions[i].name), 0);
+ if (!atom)
+ return NULL;
+
+ /* Make a constructor function for the current name. */
+ fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0);
+ if (!fun)
+ return NULL;
+
+ /* Make this constructor make objects of class Exception. */
+ fun->clasp = &ExceptionClass;
+
+ /* Make the prototype and constructor links. */
+ if (!js_SetClassPrototype(cx, fun->object, protos[i],
+ JSPROP_READONLY | JSPROP_PERMANENT)) {
+ return NULL;
+ }
+
+ /* proto bootstrap bit from JS_InitClass omitted. */
+ nameString = JS_NewStringCopyZ(cx, exceptions[i].name);
+ if (!nameString)
+ return NULL;
+
+ /* Add the name property to the prototype. */
+ if (!JS_DefineProperty(cx, protos[i], js_name_str,
+ STRING_TO_JSVAL(nameString),
+ NULL, NULL,
+ JSPROP_ENUMERATE)) {
+ return NULL;
+ }
+ }
+
+ /*
+ * Add an empty message property. (To Exception.prototype only,
+ * because this property will be the same for all the exception
+ * protos.)
+ */
+ if (!JS_DefineProperty(cx, protos[0], js_message_str,
+ STRING_TO_JSVAL(cx->runtime->emptyString),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return NULL;
+ }
+ if (!JS_DefineProperty(cx, protos[0], js_filename_str,
+ STRING_TO_JSVAL(cx->runtime->emptyString),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return NULL;
+ }
+ if (!JS_DefineProperty(cx, protos[0], js_lineno_str,
+ INT_TO_JSVAL(0),
+ NULL, NULL, JSPROP_ENUMERATE)) {
+ return NULL;
+ }
+
+ /*
+ * Add methods only to Exception.prototype, because ostensibly all
+ * exception types delegate to that.
+ */
+ if (!JS_DefineFunctions(cx, protos[0], exception_methods))
+ return NULL;
+
+ return protos[0];
+}
+
+static JSExnType errorToExceptionNum[] = {
+#define MSG_DEF(name, number, count, exception, format) \
+ exception,
+#include "js.msg"
+#undef MSG_DEF
+};
+
+#if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES )
+/* For use below... get character strings for error name and exception name */
+static struct exnname { char *name; char *exception; } errortoexnname[] = {
+#define MSG_DEF(name, number, count, exception, format) \
+ {#name, #exception},
+#include "js.msg"
+#undef MSG_DEF
+};
+#endif /* DEBUG */
+
+JSBool
+js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
+{
+ JSErrNum errorNumber;
+ JSExnType exn;
+ JSBool ok;
+ JSObject *errProto, *errObject;
+ JSString *messageStr, *filenameStr;
+ uintN lineno;
+ JSExnPrivate *privateData;
+
+ /*
+ * Tell our caller to report immediately if cx has no active frames, or if
+ * this report is just a warning.
+ */
+ JS_ASSERT(reportp);
+ if (!cx->fp || JSREPORT_IS_WARNING(reportp->flags))
+ return JS_FALSE;
+
+ /* Find the exception index associated with this error. */
+ errorNumber = (JSErrNum) reportp->errorNumber;
+ exn = errorToExceptionNum[errorNumber];
+ JS_ASSERT(exn < JSEXN_LIMIT);
+
+#if defined( DEBUG_mccabe ) && defined ( PRINTNAMES )
+ /* Print the error name and the associated exception name to stderr */
+ fprintf(stderr, "%s\t%s\n",
+ errortoexnname[errorNumber].name,
+ errortoexnname[errorNumber].exception);
+#endif
+
+ /*
+ * Return false (no exception raised) if no exception is associated
+ * with the given error number.
+ */
+ if (exn == JSEXN_NONE)
+ return JS_FALSE;
+
+ /*
+ * Prevent runaway recursion, just as the Exception native constructor
+ * must do, via cx->creatingException. If an out-of-memory error occurs,
+ * no exception object will be created, but we don't assume that OOM is
+ * the only kind of error that subroutines of this function called below
+ * might raise.
+ */
+ if (cx->creatingException)
+ return JS_FALSE;
+ cx->creatingException = JS_TRUE;
+
+ /*
+ * Try to get an appropriate prototype by looking up the corresponding
+ * exception constructor name in the scope chain of the current context's
+ * top stack frame, or in the global object if no frame is active.
+ *
+ * XXXbe hack around JSCLASS_NEW_RESOLVE code in js_LookupProperty that
+ * checks cx->fp, cx->fp->pc, and js_CodeSpec[*cx->fp->pc] in order
+ * to compute resolve flags such as JSRESOLVE_ASSIGNING. The bug
+ * is that this "internal" js_GetClassPrototype call may trigger a
+ * resolve of exceptions[exn].name if the global object uses a lazy
+ * standard class resolver (see JS_ResolveStandardClass), but the
+ * current frame and bytecode end up affecting the resolve flags.
+ */
+ {
+ JSStackFrame *fp = cx->fp;
+ jsbytecode *pc = NULL;
+
+ if (fp) {
+ pc = fp->pc;
+ fp->pc = NULL;
+ }
+ ok = js_GetClassPrototype(cx, exceptions[exn].name, &errProto);
+ if (pc)
+ fp->pc = pc;
+ if (!ok)
+ goto out;
+ }
+
+ errObject = js_NewObject(cx, &ExceptionClass, errProto, NULL);
+ if (!errObject) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ /*
+ * Set the generated Exception object early, so it won't be GC'd by a last
+ * ditch attempt to collect garbage, or a GC that otherwise nests or races
+ * under any of the following calls. If one of the following calls fails,
+ * it will overwrite this exception object with one of its own (except in
+ * case of OOM errors, of course).
+ */
+ JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
+
+ messageStr = JS_NewStringCopyZ(cx, message);
+ if (!messageStr) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ if (reportp) {
+ filenameStr = JS_NewStringCopyZ(cx, reportp->filename);
+ if (!filenameStr) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ lineno = reportp->lineno;
+ } else {
+ filenameStr = cx->runtime->emptyString;
+ lineno = 0;
+ }
+ ok = InitExceptionObject(cx, errObject, messageStr, filenameStr, lineno);
+ if (!ok)
+ goto out;
+
+ /*
+ * Construct a new copy of the error report struct, and store it in the
+ * exception object's private data. We can't use the error report struct
+ * that was passed in, because it's stack-allocated, and also because it
+ * may point to transient data in the JSTokenStream.
+ */
+ privateData = exn_newPrivate(cx, reportp);
+ if (!privateData) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ OBJ_SET_SLOT(cx, errObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(privateData));
+
+ /* Flag the error report passed in to indicate an exception was raised. */
+ reportp->flags |= JSREPORT_EXCEPTION;
+
+out:
+ cx->creatingException = JS_FALSE;
+ return ok;
+}
+#endif /* JS_HAS_ERROR_EXCEPTIONS */
+
+#if JS_HAS_EXCEPTIONS
+
+JSBool
+js_ReportUncaughtException(JSContext *cx)
+{
+ JSObject *exnObject;
+ JSString *str;
+ jsval exn;
+ JSErrorReport *reportp;
+ const char *bytes;
+
+ if (!JS_IsExceptionPending(cx))
+ return JS_FALSE;
+
+ if (!JS_GetPendingException(cx, &exn))
+ return JS_FALSE;
+
+ /*
+ * Because js_ValueToString below could error and an exception object
+ * could become unrooted, we root it here.
+ */
+ if (JSVAL_IS_OBJECT(exn) && exn != JSVAL_NULL) {
+ exnObject = JSVAL_TO_OBJECT(exn);
+ if (!js_AddRoot(cx, &exnObject, "exn.report.root"))
+ return JS_FALSE;
+ } else {
+ exnObject = NULL;
+ }
+
+#if JS_HAS_ERROR_EXCEPTIONS
+ reportp = js_ErrorFromException(cx, exn);
+#else
+ reportp = NULL;
+#endif
+
+ str = js_ValueToString(cx, exn);
+ bytes = str ? js_GetStringBytes(str) : "null";
+
+ if (reportp == NULL) {
+ /*
+ * XXXmccabe todo: Instead of doing this, synthesize an error report
+ * struct that includes the filename, lineno where the exception was
+ * originally thrown.
+ */
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_UNCAUGHT_EXCEPTION, bytes);
+ } else {
+ /* Flag the error as an exception. */
+ reportp->flags |= JSREPORT_EXCEPTION;
+ js_ReportErrorAgain(cx, bytes, reportp);
+ }
+
+ if (exnObject != NULL)
+ js_RemoveRoot(cx->runtime, &exnObject);
+ return JS_TRUE;
+}
+
+#endif /* JS_HAS_EXCEPTIONS */
diff --git a/src/dom/js/jsexn.h b/src/dom/js/jsexn.h
new file mode 100644
index 000000000..aeaab0a58
--- /dev/null
+++ b/src/dom/js/jsexn.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS runtime exception classes.
+ */
+
+#ifndef jsexn_h___
+#define jsexn_h___
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * Initialize the exception constructor/prototype hierarchy.
+ */
+extern JSObject *
+js_InitExceptionClasses(JSContext *cx, JSObject *obj);
+
+/*
+ * String constants naming the exception classes.
+ */
+extern const char js_Error_str[];
+extern const char js_InternalError_str[];
+extern const char js_EvalError_str[];
+extern const char js_RangeError_str[];
+extern const char js_ReferenceError_str[];
+extern const char js_SyntaxError_str[];
+extern const char js_TypeError_str[];
+extern const char js_URIError_str[];
+
+/*
+ * Given a JSErrorReport, check to see if there is an exception associated with
+ * the error number. If there is, then create an appropriate exception object,
+ * set it as the pending exception, and set the JSREPORT_EXCEPTION flag on the
+ * error report. Exception-aware host error reporters should probably ignore
+ * error reports so flagged. Returns JS_TRUE if an associated exception is
+ * found and set, JS_FALSE otherwise..
+ */
+extern JSBool
+js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp);
+
+/*
+ * Called if a JS API call to js_Execute or js_InternalCall fails; calls the
+ * error reporter with the error report associated with any uncaught exception
+ * that has been raised. Returns true if there was an exception pending, and
+ * the error reporter was actually called.
+ *
+ * The JSErrorReport * that the error reporter is called with is currently
+ * associated with a JavaScript object, and is not guaranteed to persist after
+ * the object is collected. Any persistent uses of the JSErrorReport contents
+ * should make their own copy.
+ *
+ * The flags field of the JSErrorReport will have the JSREPORT_EXCEPTION flag
+ * set; embeddings that want to silently propagate JavaScript exceptions to
+ * other contexts may want to use an error reporter that ignores errors with
+ * this flag.
+ */
+extern JSBool
+js_ReportUncaughtException(JSContext *cx);
+
+extern JSErrorReport *
+js_ErrorFromException(JSContext *cx, jsval exn);
+
+JS_END_EXTERN_C
+
+#endif /* jsexn_h___ */
diff --git a/src/dom/js/jsfile.c b/src/dom/js/jsfile.c
new file mode 100644
index 000000000..ef5e93b29
--- /dev/null
+++ b/src/dom/js/jsfile.c
@@ -0,0 +1,2610 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS File object
+ */
+#if JS_HAS_FILE_OBJECT
+
+#include "jsstddef.h"
+
+/* ----------------- Platform-specific includes and defines ----------------- */
+#ifdef XP_MAC
+# define FILESEPARATOR ':'
+# define FILESEPARATOR2 '\0'
+# define CURRENT_DIR "HARD DISK:Desktop Folder"
+/* TODO: #include <???> */
+#elif defined(XP_WIN) || defined(XP_OS2)
+# include <direct.h>
+# include <io.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# define FILESEPARATOR '\\'
+# define FILESEPARATOR2 '/'
+# define CURRENT_DIR "c:\\"
+# define POPEN _popen
+# define PCLOSE _pclose
+#elif defined(XP_UNIX) || defined(XP_BEOS)
+# include <strings.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# define FILESEPARATOR '/'
+# define FILESEPARATOR2 '\0'
+# define CURRENT_DIR "/"
+# define POPEN popen
+# define PCLOSE pclose
+#endif
+
+/* --------------- Platform-independent includes and defines ---------------- */
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsdate.h"
+#include "jsdbgapi.h"
+#include "jsemit.h"
+#include "jsfun.h"
+#include "jslock.h"
+#include "jsobj.h"
+#include "jsparse.h"
+#include "jsscan.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include <string.h>
+
+/* NSPR dependencies */
+#include "prio.h"
+#include "prerror.h"
+
+#define SPECIAL_FILE_STRING "Special File"
+#define CURRENTDIR_PROPERTY "currentDir"
+#define SEPARATOR_PROPERTY "separator"
+#define FILE_CONSTRUCTOR "File"
+#define PIPE_SYMBOL '|'
+
+#define ASCII 0
+#define UTF8 1
+#define UCS2 2
+
+#define asciistring "text"
+#define utfstring "binary"
+#define unicodestring "unicode"
+
+#define MAX_PATH_LENGTH 1024
+#define MODE_SIZE 256
+#define NUMBER_SIZE 32
+#define MAX_LINE_LENGTH 256
+#define URL_PREFIX "file://"
+
+#define STDINPUT_NAME "Standard input stream"
+#define STDOUTPUT_NAME "Standard output stream"
+#define STDERROR_NAME "Standard error stream"
+
+#define RESOLVE_PATH js_canonicalPath /* js_absolutePath */
+
+/* Error handling */
+typedef enum JSFileErrNum {
+#define MSG_DEF(name, number, count, exception, format) \
+ name = number,
+#include "jsfile.msg"
+#undef MSG_DEF
+ JSFileErr_Limit
+#undef MSGDEF
+} JSFileErrNum;
+
+#define JSFILE_HAS_DFLT_MSG_STRINGS 1
+
+JSErrorFormatString JSFile_ErrorFormatString[JSFileErr_Limit] = {
+#if JSFILE_HAS_DFLT_MSG_STRINGS
+#define MSG_DEF(name, number, count, exception, format) \
+ { format, count } ,
+#else
+#define MSG_DEF(name, number, count, exception, format) \
+ { NULL, count } ,
+#endif
+#include "jsfile.msg"
+#undef MSG_DEF
+};
+
+const JSErrorFormatString *
+JSFile_GetErrorMessage(void *userRef, const char *locale,
+ const uintN errorNumber)
+{
+ if ((errorNumber > 0) && (errorNumber < JSFileErr_Limit))
+ return &JSFile_ErrorFormatString[errorNumber];
+ else
+ return NULL;
+}
+
+#define JSFILE_CHECK_NATIVE(op) \
+ if(file->isNative){ \
+ JS_ReportWarning(cx, "Cannot call or access \"%s\" on native file %s", \
+ op, file->path); \
+ goto out; \
+ }
+
+#define JSFILE_CHECK_WRITE \
+ if (!file->isOpen){ \
+ JS_ReportWarning(cx, \
+ "File %s is closed, will open it for writing, proceeding", \
+ file->path); \
+ js_FileOpen(cx, obj, file, "write,append,create"); \
+ }else \
+ if(!js_canWrite(cx, file)){ \
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
+ JSFILEMSG_CANNOT_WRITE, file->path); \
+ goto out; \
+ }
+
+#define JSFILE_CHECK_READ \
+ if (!file->isOpen){ \
+ JS_ReportWarning(cx, \
+ "File %s is closed, will open it for reading, proceeding", \
+ file->path); \
+ js_FileOpen(cx, obj, file, "read"); \
+ }else \
+ if(!js_canRead(cx, file)){ \
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
+ JSFILEMSG_CANNOT_READ, file->path); \
+ goto out; \
+ }
+
+#define JSFILE_CHECK_OPEN(op) \
+ if(!file->isOpen){ \
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
+ JSFILEMSG_FILE_MUST_BE_CLOSED, op); \
+ goto out; \
+ }
+
+#define JSFILE_CHECK_CLOSED(op) \
+ if(file->isOpen){ \
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
+ JSFILEMSG_FILE_MUST_BE_OPEN, op); \
+ goto out; \
+ }
+
+#define JSFILE_CHECK_ONE_ARG(op) \
+ if (argc!=1){ \
+ char str[NUMBER_SIZE]; \
+ \
+ sprintf(str, "%d", argc); \
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
+ JSFILEMSG_EXPECTS_ONE_ARG_ERROR, op, str); \
+ goto out; \
+ }
+
+
+/*
+ Security mechanism, should define a callback for this.
+ The parameters are as follows:
+ SECURITY_CHECK(JSContext *cx, JSPrincipals *ps, char *op_name, JSFile *file)
+*/
+#define SECURITY_CHECK(cx, ps, op, file) \
+ /* Define a callback here... */
+
+
+/* Structure representing the file internally */
+typedef struct JSFile {
+ char *path; /* the path to the file. */
+ JSBool isOpen;
+ JSString *linebuffer; /* temp buffer used by readln. */
+ int32 mode; /* mode used to open the file: read, write, append, create, etc.. */
+ int32 type; /* Asciiz, utf, unicode */
+ char byteBuffer[3]; /* bytes read in advance by js_FileRead ( UTF8 encoding ) */
+ jsint nbBytesInBuf; /* number of bytes stored in the buffer above */
+ jschar charBuffer; /* character read in advance by readln ( mac files only ) */
+ JSBool charBufferUsed; /* flag indicating if the buffer above is being used */
+ JSBool hasRandomAccess; /* can the file be randomly accessed? false for stdin, and
+ UTF-encoded files. */
+ JSBool hasAutoflush; /* should we force a flush for each line break? */
+ JSBool isNative; /* if the file is using OS-specific file FILE type */
+ /* We can actually put the following two in a union since they should never be used at the same time */
+ PRFileDesc *handle; /* the handle for the file, if open. */
+ FILE *nativehandle; /* native handle, for stuff NSPR doesn't do. */
+ JSBool isPipe; /* if the file is really an OS pipe */
+} JSFile;
+
+/* a few forward declarations... */
+static JSClass file_class;
+JS_PUBLIC_API(JSObject*) js_NewFileObject(JSContext *cx, char *filename);
+static JSBool file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+/* --------------------------- New filename manipulation procesures -------------------------- */
+/* assumes we don't have leading/trailing spaces */
+static JSBool
+js_filenameHasAPipe(const char *filename)
+{
+#ifdef XP_MAC
+ /* pipes are not supported on the MAC */
+ return JS_FALSE;
+#else
+ if(!filename) return JS_FALSE;
+ return filename[0]==PIPE_SYMBOL ||
+ filename[strlen(filename)-1]==PIPE_SYMBOL;
+#endif
+}
+
+static JSBool
+js_isAbsolute(const char *name)
+{
+#if defined(XP_WIN) || defined(XP_OS2)
+ return (strlen(name)>1)?((name[1]==':')?JS_TRUE:JS_FALSE):JS_FALSE;
+#else
+ return (name[0]
+# if defined(XP_UNIX) || defined(XP_BEOS)
+ ==
+# else
+ !=
+# endif
+ FILESEPARATOR)?JS_TRUE:JS_FALSE;
+#endif
+}
+
+/*
+ Concatinates base and name to produce a valid filename.
+ Returned string must be freed.
+*/
+static char*
+js_combinePath(JSContext *cx, const char *base, const char *name)
+{
+ int len = strlen(base);
+ char* result = (char*)JS_malloc(cx, len+strlen(name)+2);
+
+ if (!result) return NULL;
+
+ strcpy(result, base);
+
+ if (base[len-1]!=FILESEPARATOR
+#if defined(XP_WIN) || defined(XP_OS2)
+ && base[len-1]!=FILESEPARATOR2
+#endif
+ ) {
+ result[len] = FILESEPARATOR;
+ result[len+1] = '\0';
+ }
+ strcat(result, name);
+ return result;
+}
+
+/* Extract the last component from a path name. Returned string must be freed */
+static char *
+js_fileBaseName(JSContext *cx, const char *pathname)
+{
+ jsint index, aux;
+ char *result;
+
+#if defined(XP_WIN) || defined(XP_OS2)
+ /* First, get rid of the drive selector */
+ if ((strlen(pathname)>=2)&&(pathname[1]==':')) {
+ pathname = &pathname[2];
+ }
+#endif
+ index = strlen(pathname)-1;
+ /*
+ remove trailing separators -- don't necessarily need to check for
+ FILESEPARATOR2, but that's fine
+ */
+ while ((index>0)&&((pathname[index]==FILESEPARATOR)||
+ (pathname[index]==FILESEPARATOR2))) index--;
+ aux = index;
+ /* now find the next separator */
+ while ((index>=0)&&(pathname[index]!=FILESEPARATOR)&&
+ (pathname[index]!=FILESEPARATOR2)) index--;
+ /* allocate and copy */
+ result = (char*)JS_malloc(cx, aux-index+1);
+ if (!result) return NULL;
+ strncpy(result, &pathname[index+1], aux-index);
+ result[aux-index] = '\0';
+ return result;
+}
+
+/*
+ Returns everytynig but the last component from a path name.
+ Returned string must be freed. Returned string must be freed.
+*/
+static char *
+js_fileDirectoryName(JSContext *cx, const char *pathname)
+{
+ jsint index;
+ char *result;
+
+#if defined(XP_WIN) || defined(XP_OS2)
+ char drive = '\0';
+ const char *oldpathname = pathname;
+
+ /* First, get rid of the drive selector */
+ if ((strlen(pathname)>=2)&&(pathname[1]==':')) {
+ drive = pathname[0];
+ pathname = &pathname[2];
+ }
+#endif
+ index = strlen(pathname)-1;
+ while ((index>0)&&((pathname[index]==FILESEPARATOR)||
+ (pathname[index]==FILESEPARATOR2))) index--;
+ while ((index>0)&&(pathname[index]!=FILESEPARATOR)&&
+ (pathname[index]!=FILESEPARATOR2)) index--;
+
+ if (index>=0){
+ result = (char*)JS_malloc(cx, index+4);
+ if (!result) return NULL;
+#if defined(XP_WIN) || defined(XP_OS2)
+ if (drive!='\0') {
+ result[0] = toupper(drive);
+ result[1] = ':';
+ strncpy(&result[2], pathname, index);
+ result[index+3] = '\0';
+ }else
+#endif
+ {
+ strncpy(result, pathname, index);
+ result[index] = '\0';
+ }
+
+ /* add terminating separator */
+ index = strlen(result)-1;
+ result[index] = FILESEPARATOR;
+ result[index+1] = '\0';
+ } else{
+#if defined(XP_WIN) || defined(XP_OS2)
+ result = JS_strdup(cx, oldpathname); /* may include drive selector */
+#else
+ result = JS_strdup(cx, pathname);
+#endif
+ }
+
+ return result;
+}
+
+static char *
+js_absolutePath(JSContext *cx, const char * path)
+{
+ JSObject *obj;
+ JSString *str;
+ jsval prop;
+
+ if (js_isAbsolute(path)){
+ return JS_strdup(cx, path);
+ }else{
+ obj = JS_GetGlobalObject(cx);
+ if (!JS_GetProperty(cx, obj, FILE_CONSTRUCTOR, &prop)) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR);
+ return JS_strdup(cx, path);
+ }
+ obj = JSVAL_TO_OBJECT(prop);
+ if (!JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, &prop)) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR);
+ return JS_strdup(cx, path);
+ }
+ str = JS_ValueToString(cx, prop);
+ if (!str ) {
+ return JS_strdup(cx, path);
+ }
+ /* should we have an array of curr dirs indexed by drive for windows? */
+ return js_combinePath(cx, JS_GetStringBytes(str), path);
+ }
+}
+
+/* Side effect: will remove spaces in the beginning/end of the filename */
+static char *
+js_canonicalPath(JSContext *cx, char *oldpath)
+{
+ char *tmp;
+ char *path = oldpath;
+ char *base, *dir, *current, *result;
+ jsint c;
+ jsint back = 0;
+ unsigned int i = 0, j = strlen(path)-1;
+
+ /* This is probably optional */
+ /* Remove possible spaces in the beginning and end */
+ while(i<strlen(path)-1 && path[i]==' ') i++;
+ while(j>=0 && path[j]==' ') j--;
+
+ tmp = JS_malloc(cx, j-i+2);
+ strncpy(tmp, &path[i], j-i+1);
+ tmp[j-i+1] = '\0';
+
+ path = tmp;
+
+ /* pipe support */
+ if(js_filenameHasAPipe(path))
+ return JS_strdup(cx, path);
+ /* file:// support */
+ if(!strncmp(path, URL_PREFIX, strlen(URL_PREFIX)))
+ return js_canonicalPath(cx, &path[strlen(URL_PREFIX)-1]);
+
+ if (!js_isAbsolute(path))
+ path = js_absolutePath(cx, path);
+ else
+ path = JS_strdup(cx, path);
+
+ result = JS_strdup(cx, "");
+
+ current = path;
+
+ base = js_fileBaseName(cx, current);
+ dir = js_fileDirectoryName(cx, current);
+
+ /* TODO: MAC -- not going to work??? */
+ while (strcmp(dir, current)) {
+ if (!strcmp(base, "..")) {
+ back++;
+ } else
+ if(!strcmp(base, ".")){
+ /* ??? */
+ } else {
+ if (back>0)
+ back--;
+ else {
+ tmp = result;
+ result = JS_malloc(cx, strlen(base)+1+strlen(tmp)+1);
+ if (!result) {
+ JS_free(cx, dir);
+ JS_free(cx, base);
+ JS_free(cx, current);
+ return NULL;
+ }
+ strcpy(result, base);
+ c = strlen(result);
+ if (*tmp) {
+ result[c] = FILESEPARATOR;
+ result[c+1] = '\0';
+ strcat(result, tmp);
+ }
+ JS_free(cx, tmp);
+ }
+ }
+ JS_free(cx, current);
+ JS_free(cx, base);
+ current = dir;
+ base = js_fileBaseName(cx, current);
+ dir = js_fileDirectoryName(cx, current);
+ }
+
+ tmp = result;
+ result = JS_malloc(cx, strlen(dir)+1+strlen(tmp)+1);
+ if (!result) {
+ JS_free(cx, dir);
+ JS_free(cx, base);
+ JS_free(cx, current);
+ return NULL;
+ }
+ strcpy(result, dir);
+ c = strlen(result);
+ if (tmp[0]!='\0') {
+ if ((result[c-1]!=FILESEPARATOR)&&(result[c-1]!=FILESEPARATOR2)) {
+ result[c] = FILESEPARATOR;
+ result[c+1] = '\0';
+ }
+ strcat(result, tmp);
+ }
+ JS_free(cx, tmp);
+ JS_free(cx, dir);
+ JS_free(cx, base);
+ JS_free(cx, current);
+
+ return result;
+}
+
+/* -------------------------- Text conversion ------------------------------- */
+/* The following is ripped from libi18n/unicvt.c and include files.. */
+
+/*
+ * UTF8 defines and macros
+ */
+#define ONE_OCTET_BASE 0x00 /* 0xxxxxxx */
+#define ONE_OCTET_MASK 0x7F /* x1111111 */
+#define CONTINUING_OCTET_BASE 0x80 /* 10xxxxxx */
+#define CONTINUING_OCTET_MASK 0x3F /* 00111111 */
+#define TWO_OCTET_BASE 0xC0 /* 110xxxxx */
+#define TWO_OCTET_MASK 0x1F /* 00011111 */
+#define THREE_OCTET_BASE 0xE0 /* 1110xxxx */
+#define THREE_OCTET_MASK 0x0F /* 00001111 */
+#define FOUR_OCTET_BASE 0xF0 /* 11110xxx */
+#define FOUR_OCTET_MASK 0x07 /* 00000111 */
+#define FIVE_OCTET_BASE 0xF8 /* 111110xx */
+#define FIVE_OCTET_MASK 0x03 /* 00000011 */
+#define SIX_OCTET_BASE 0xFC /* 1111110x */
+#define SIX_OCTET_MASK 0x01 /* 00000001 */
+
+#define IS_UTF8_1ST_OF_1(x) (( (x)&~ONE_OCTET_MASK ) == ONE_OCTET_BASE)
+#define IS_UTF8_1ST_OF_2(x) (( (x)&~TWO_OCTET_MASK ) == TWO_OCTET_BASE)
+#define IS_UTF8_1ST_OF_3(x) (( (x)&~THREE_OCTET_MASK) == THREE_OCTET_BASE)
+#define IS_UTF8_1ST_OF_4(x) (( (x)&~FOUR_OCTET_MASK ) == FOUR_OCTET_BASE)
+#define IS_UTF8_1ST_OF_5(x) (( (x)&~FIVE_OCTET_MASK ) == FIVE_OCTET_BASE)
+#define IS_UTF8_1ST_OF_6(x) (( (x)&~SIX_OCTET_MASK ) == SIX_OCTET_BASE)
+#define IS_UTF8_2ND_THRU_6TH(x) \
+ (( (x)&~CONTINUING_OCTET_MASK ) == CONTINUING_OCTET_BASE)
+#define IS_UTF8_1ST_OF_UCS2(x) \
+ IS_UTF8_1ST_OF_1(x) \
+ || IS_UTF8_1ST_OF_2(x) \
+ || IS_UTF8_1ST_OF_3(x)
+
+
+#define MAX_UCS2 0xFFFF
+#define DEFAULT_CHAR 0x003F /* Default char is "?" */
+#define BYTE_MASK 0xBF
+#define BYTE_MARK 0x80
+
+
+/* Function: one_ucs2_to_utf8_char
+ *
+ * Function takes one UCS-2 char and writes it to a UTF-8 buffer.
+ * We need a UTF-8 buffer because we don't know before this
+ * function how many bytes of utf-8 data will be written. It also
+ * takes a pointer to the end of the UTF-8 buffer so that we don't
+ * overwrite data. This function returns the number of UTF-8 bytes
+ * of data written, or -1 if the buffer would have been overrun.
+ */
+
+#define LINE_SEPARATOR 0x2028
+#define PARAGRAPH_SEPARATOR 0x2029
+static int16 one_ucs2_to_utf8_char(unsigned char *tobufp,
+ unsigned char *tobufendp, uint16 onechar)
+{
+
+ int16 numUTF8bytes = 0;
+
+ if((onechar == LINE_SEPARATOR)||(onechar == PARAGRAPH_SEPARATOR))
+ {
+ strcpy((char*)tobufp, "\n");
+ return strlen((char*)tobufp);;
+ }
+
+ if (onechar < 0x80) { numUTF8bytes = 1;
+ } else if (onechar < 0x800) { numUTF8bytes = 2;
+ } else if (onechar <= MAX_UCS2) { numUTF8bytes = 3;
+ } else { numUTF8bytes = 2;
+ onechar = DEFAULT_CHAR;
+ }
+
+ tobufp += numUTF8bytes;
+
+ /* return error if we don't have space for the whole character */
+ if (tobufp > tobufendp) {
+ return(-1);
+ }
+
+
+ switch(numUTF8bytes) {
+
+ case 3: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6;
+ *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6;
+ *--tobufp = onechar | THREE_OCTET_BASE;
+ break;
+
+ case 2: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6;
+ *--tobufp = onechar | TWO_OCTET_BASE;
+ break;
+ case 1: *--tobufp = (unsigned char)onechar; break;
+ }
+
+ return(numUTF8bytes);
+}
+
+/*
+ * utf8_to_ucs2_char
+ *
+ * Convert a utf8 multibyte character to ucs2
+ *
+ * inputs: pointer to utf8 character(s)
+ * length of utf8 buffer ("read" length limit)
+ * pointer to return ucs2 character
+ *
+ * outputs: number of bytes in the utf8 character
+ * -1 if not a valid utf8 character sequence
+ * -2 if the buffer is too short
+ */
+static int16
+utf8_to_ucs2_char(const unsigned char *utf8p, int16 buflen, uint16 *ucs2p)
+{
+ uint16 lead, cont1, cont2;
+
+ /*
+ * Check for minimum buffer length
+ */
+ if ((buflen < 1) || (utf8p == NULL)) {
+ return -2;
+ }
+ lead = (uint16) (*utf8p);
+
+ /*
+ * Check for a one octet sequence
+ */
+ if (IS_UTF8_1ST_OF_1(lead)) {
+ *ucs2p = lead & ONE_OCTET_MASK;
+ return 1;
+ }
+
+ /*
+ * Check for a two octet sequence
+ */
+ if (IS_UTF8_1ST_OF_2(*utf8p)) {
+ if (buflen < 2)
+ return -2;
+ cont1 = (uint16) *(utf8p+1);
+ if (!IS_UTF8_2ND_THRU_6TH(cont1))
+ return -1;
+ *ucs2p = (lead & TWO_OCTET_MASK) << 6;
+ *ucs2p |= cont1 & CONTINUING_OCTET_MASK;
+ return 2;
+ }
+
+ /*
+ * Check for a three octet sequence
+ */
+ else if (IS_UTF8_1ST_OF_3(lead)) {
+ if (buflen < 3)
+ return -2;
+ cont1 = (uint16) *(utf8p+1);
+ cont2 = (uint16) *(utf8p+2);
+ if ( (!IS_UTF8_2ND_THRU_6TH(cont1))
+ || (!IS_UTF8_2ND_THRU_6TH(cont2)))
+ return -1;
+ *ucs2p = (lead & THREE_OCTET_MASK) << 12;
+ *ucs2p |= (cont1 & CONTINUING_OCTET_MASK) << 6;
+ *ucs2p |= cont2 & CONTINUING_OCTET_MASK;
+ return 3;
+ }
+ else { /* not a valid utf8/ucs2 character */
+ return -1;
+ }
+}
+
+/* ----------------------------- Helper functions --------------------------- */
+/* Ripped off from lm_win.c .. */
+/* where is strcasecmp?.. for now, it's case sensitive..
+ *
+ * strcasecmp is in strings.h, but on windows it's called _stricmp...
+ * will need to #ifdef this
+*/
+
+static int32
+js_FileHasOption(JSContext *cx, const char *oldoptions, const char *name)
+{
+ char *comma, *equal, *current;
+ char *options = JS_strdup(cx, oldoptions);
+ int32 found = 0;
+
+ current = options;
+ for (;;) {
+ comma = strchr(current, ',');
+ if (comma) *comma = '\0';
+ equal = strchr(current, '=');
+ if (equal) *equal = '\0';
+ if (strcmp(current, name) == 0) {
+ if (!equal || strcmp(equal + 1, "yes") == 0)
+ found = 1;
+ else
+ found = atoi(equal + 1);
+ }
+ if (equal) *equal = '=';
+ if (comma) *comma = ',';
+ if (found || !comma)
+ break;
+ current = comma + 1;
+ }
+ JS_free(cx, options);
+ return found;
+}
+
+/* empty the buffer */
+static void
+js_ResetBuffers(JSFile * file)
+{
+ file->charBufferUsed = JS_FALSE;
+ file->nbBytesInBuf = 0;
+ file->linebuffer = NULL; /* TODO: check for mem. leak? */
+}
+
+/* Reset file attributes */
+static void
+js_ResetAttributes(JSFile * file){
+ file->mode = file->type = 0;
+ file->isOpen = JS_FALSE;
+ file->handle = NULL;
+ file->nativehandle = NULL;
+ file->hasRandomAccess = JS_TRUE; /* innocent until proven guilty */
+ file->hasAutoflush = JS_FALSE;
+ file->isNative = JS_FALSE;
+ file->isPipe = JS_FALSE;
+
+ js_ResetBuffers(file);
+}
+
+static JSBool
+js_FileOpen(JSContext *cx, JSObject *obj, JSFile *file, char *mode){
+ JSString *type, *mask;
+ jsval v[2];
+ jsval rval;
+
+ type = JS_InternString(cx, asciistring);
+ mask = JS_NewStringCopyZ(cx, mode);
+ v[0] = STRING_TO_JSVAL(mask);
+ v[1] = STRING_TO_JSVAL(type);
+
+ if (!file_open(cx, obj, 2, v, &rval)) {
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+/* Buffered version of PR_Read. Used by js_FileRead */
+static int32
+js_BufferedRead(JSFile * f, char *buf, int32 len)
+{
+ int32 count = 0;
+
+ while (f->nbBytesInBuf>0&&len>0) {
+ buf[0] = f->byteBuffer[0];
+ f->byteBuffer[0] = f->byteBuffer[1];
+ f->byteBuffer[1] = f->byteBuffer[2];
+ f->nbBytesInBuf--;
+ len--;
+ buf+=1;
+ count++;
+ }
+
+ if (len>0) {
+ count+= (!f->isNative)?
+ PR_Read(f->handle, buf, len):
+ fread(buf, 1, len, f->nativehandle);
+ }
+ return count;
+}
+
+static int32
+js_FileRead(JSContext *cx, JSFile * file, jschar*buf, int32 len, int32 mode)
+{
+ unsigned char*aux;
+ int32 count, i;
+ jsint remainder;
+ unsigned char utfbuf[3];
+
+ if (file->charBufferUsed) {
+ buf[0] = file->charBuffer;
+ buf++;
+ len--;
+ file->charBufferUsed = JS_FALSE;
+ }
+
+ switch (mode) {
+ case ASCII:
+ aux = (unsigned char*)JS_malloc(cx, len);
+ if (!aux) {
+ return 0;
+ }
+ count = js_BufferedRead(file, aux, len);
+ if (count==-1) {
+ JS_free(cx, aux);
+ return 0;
+ }
+ for (i = 0;i<len;i++) {
+ buf[i] = (jschar)aux[i];
+ }
+ JS_free(cx, aux);
+ break;
+ case UTF8:
+ remainder = 0;
+ for (count = 0;count<len;count++) {
+ i = js_BufferedRead(file, utfbuf+remainder, 3-remainder);
+ if (i<=0) {
+ return count;
+ }
+ i = utf8_to_ucs2_char(utfbuf, (int16)i, &buf[count] );
+ if (i<0) {
+ return count;
+ } else {
+ if (i==1) {
+ utfbuf[0] = utfbuf[1];
+ utfbuf[1] = utfbuf[2];
+ remainder = 2;
+ } else
+ if (i==2) {
+ utfbuf[0] = utfbuf[2];
+ remainder = 1;
+ } else
+ if (i==3)
+ remainder = 0;
+ }
+ }
+ while (remainder>0) {
+ file->byteBuffer[file->nbBytesInBuf] = utfbuf[0];
+ file->nbBytesInBuf++;
+ utfbuf[0] = utfbuf[1];
+ utfbuf[1] = utfbuf[2];
+ remainder--;
+ }
+ break;
+ case UCS2:
+ count = js_BufferedRead(file, (char*)buf, len*2)>>1;
+ if (count==-1) {
+ return 0;
+ }
+ break;
+ }
+
+ if(count==-1){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "read", file->path);
+ }
+
+ return count;
+}
+
+static int32
+js_FileSeek(JSContext *cx, JSFile *file, int32 len, int32 mode)
+{
+ int32 count, i;
+ jsint remainder;
+ unsigned char utfbuf[3];
+ jschar tmp;
+
+ switch (mode) {
+ case ASCII:
+ count = PR_Seek(file->handle, len, PR_SEEK_CUR);
+ break;
+ case UTF8:
+ remainder = 0;
+ for (count = 0;count<len;count++) {
+ i = js_BufferedRead(file, utfbuf+remainder, 3-remainder);
+ if (i<=0) {
+ return 0;
+ }
+ i = utf8_to_ucs2_char(utfbuf, (int16)i, &tmp );
+ if (i<0) {
+ return 0;
+ } else {
+
+ if (i==1) {
+ utfbuf[0] = utfbuf[1];
+ utfbuf[1] = utfbuf[2];
+ remainder = 2;
+ } else
+ if (i==2) {
+ utfbuf[0] = utfbuf[2];
+ remainder = 1;
+ } else
+ if (i==3)
+ remainder = 0;
+ }
+ }
+ while (remainder>0) {
+ file->byteBuffer[file->nbBytesInBuf] = utfbuf[0];
+ file->nbBytesInBuf++;
+ utfbuf[0] = utfbuf[1];
+ utfbuf[1] = utfbuf[2];
+ remainder--;
+ }
+ break;
+ case UCS2:
+ count = PR_Seek(file->handle, len*2, PR_SEEK_CUR)/2;
+ break;
+ }
+
+ if(count==-1){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "seek", file->path);
+ }
+
+ return count;
+}
+
+static int32
+js_FileWrite(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode)
+{
+ unsigned char *aux;
+ int32 count, i, j;
+ unsigned char *utfbuf;
+
+ switch (mode) {
+ case ASCII:
+ aux = (unsigned char*)JS_malloc(cx, len);
+ if (!aux) return 0;
+
+ for (i = 0; i<len; i++) {
+ aux[i]=buf[i]%256;
+ }
+
+ count = (!file->isNative)?
+ PR_Write(file->handle, aux, len):
+ fwrite(aux, 1, len, file->nativehandle);
+
+ if (count==-1) {
+ JS_free(cx, aux);
+ return 0;
+ }
+ JS_free(cx, aux);
+ break;
+ case UTF8:
+ utfbuf = (unsigned char*)JS_malloc(cx, len*3);
+ if (!utfbuf) return 0;
+ i = 0;
+ for (count = 0;count<len;count++) {
+ j = one_ucs2_to_utf8_char(utfbuf+i, utfbuf+len*3, buf[count]);
+ if (j==-1) {
+ JS_free(cx, utfbuf);
+ return 0;
+ }
+ i+=j;
+ }
+ j = (!file->isNative)?
+ PR_Write(file->handle, utfbuf, i):
+ fwrite(utfbuf, 1, i, file->nativehandle);
+
+ if (j<i) {
+ JS_free(cx, utfbuf);
+ return 0;
+ }
+ JS_free(cx, utfbuf);
+ break;
+ case UCS2:
+ count = (!file->isNative)?
+ PR_Write(file->handle, buf, len*2)>>1:
+ fwrite(buf, 1, len*2, file->nativehandle)>>1;
+
+ if (count==-1) {
+ return 0;
+ }
+ break;
+ }
+ if(count==-1){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "write", file->path);
+ }
+ return count;
+}
+
+/* ----------------------------- Property checkers -------------------------- */
+static JSBool
+js_exists(JSContext *cx, JSFile *file)
+{
+ if(!file->isNative){
+ return (PR_Access(file->path, PR_ACCESS_EXISTS)==PR_SUCCESS);
+ }else{
+ /* doesn't make sense for a pipe of stdstream */
+ return JS_FALSE;
+ }
+}
+
+static JSBool
+js_canRead(JSContext *cx, JSFile *file)
+{
+ if(!file->isNative){
+ if(file->isOpen&&!(file->mode&PR_RDONLY)) return JS_FALSE;
+ return (PR_Access(file->path, PR_ACCESS_READ_OK)==PR_SUCCESS);
+ }else{
+ if(file->isPipe){
+ /* pipe open for reading */
+ return file->path[0]==PIPE_SYMBOL;
+ }else{
+ return !strcmp(file->path, STDINPUT_NAME);
+ }
+ }
+}
+
+static JSBool
+js_canWrite(JSContext *cx, JSFile *file)
+{
+ if(!file->isNative){
+ if(file->isOpen&&!(file->mode&PR_WRONLY)) return JS_FALSE;
+ return (PR_Access(file->path, PR_ACCESS_WRITE_OK)==PR_SUCCESS);
+ }else{
+ if(file->isPipe){
+ /* pipe open for writing */
+ return file->path[strlen(file->path)-1]==PIPE_SYMBOL;
+ }else{
+ return !strcmp(file->path, STDOUTPUT_NAME) ||
+ !strcmp(file->path, STDERROR_NAME);
+ }
+ }
+}
+
+static JSBool
+js_isFile(JSContext *cx, JSFile *file)
+{
+ if(!file->isNative){
+ PRFileInfo info;
+
+ if ((file->isOpen)?
+ PR_GetOpenFileInfo(file->handle, &info):
+ PR_GetFileInfo(file->path, &info)!=PR_SUCCESS){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
+ return JS_FALSE;
+ }else
+ return (info.type==PR_FILE_FILE);
+ }else{
+ /* doesn't make sense for a pipe of stdstream */
+ return JS_FALSE;
+ }
+}
+
+static JSBool
+js_isDirectory(JSContext *cx, JSFile *file)
+{
+ if(!file->isNative){
+ PRFileInfo info;
+
+ /* hack needed to get get_property to work */
+ if(!js_exists(cx, file)) return JS_FALSE;
+
+ if ((file->isOpen)?
+ PR_GetOpenFileInfo(file->handle, &info):
+ PR_GetFileInfo(file->path, &info)!=PR_SUCCESS){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
+ return JS_FALSE;
+ }else
+ return (info.type==PR_FILE_DIRECTORY);
+ }else{
+ /* doesn't make sense for a pipe of stdstream */
+ return JS_FALSE;
+ }
+}
+
+static jsval
+js_size(JSContext *cx, JSFile *file)
+{
+ PRFileInfo info;
+
+ JSFILE_CHECK_NATIVE("size");
+
+ if ((file->isOpen)?
+ PR_GetOpenFileInfo(file->handle, &info):
+ PR_GetFileInfo(file->path, &info)!=PR_SUCCESS){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
+ goto out;
+ }else
+ return INT_TO_JSVAL(info.size);
+out:
+ return JSVAL_VOID;
+}
+
+/* Return the parent object */
+static jsval
+js_parent(JSContext *cx, JSFile *file)
+{
+ char *str;
+
+ /* since we only care about pipes and native files, return NULL */
+ if(file->isNative) return JSVAL_VOID;
+
+ str = js_fileDirectoryName(cx, file->path);
+ /* root.parent = null ??? */
+ if(!strcmp(file->path, str) ||
+ (!strncmp(str, file->path, strlen(str)-1)&&
+ file->path[strlen(file->path)]-1)==FILESEPARATOR){
+ return JSVAL_NULL;
+ }else{
+ return OBJECT_TO_JSVAL(js_NewFileObject(cx, str));
+ JS_free(cx, str);
+ }
+}
+
+static jsval
+js_name(JSContext *cx, JSFile *file){
+ return file->isPipe?
+ JSVAL_VOID:
+ STRING_TO_JSVAL(JS_NewStringCopyZ(cx, js_fileBaseName(cx, file->path)));
+}
+
+/* ------------------------------ File object methods ---------------------------- */
+static JSBool
+file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ JSString *strmode, *strtype;
+ char *ctype, *mode;
+ int32 mask, type;
+ int len;
+
+ SECURITY_CHECK(cx, NULL, "open", file);
+
+ /* A native file that is already open */
+ if(file->isOpen && file->isNative){
+ JS_ReportWarning(cx, "Native file %s is already open, proceeding",
+ file->path);
+ goto good;
+ }
+
+ /* Close before proceeding */
+ if (file->isOpen) {
+ JS_ReportWarning(cx,
+ "File %s is already open, we will close it and reopen, proceeding",
+ file->path);
+ if(!file_close(cx, obj, 0, NULL, rval)) goto out;
+ }
+
+ if(js_isDirectory(cx, file)){
+ JS_ReportWarning(cx, "%s seems to be a directory, there is no point in "
+ "trying to open it, proceeding", file->path);
+ goto good;
+ }
+
+ /* Path must be defined at this point */
+ len = strlen(file->path);
+
+ /* Mode */
+ if (argc>=1){
+ strmode = JS_ValueToString(cx, argv[0]);
+ if (!strmode){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR, argv[0]);
+ goto out;
+ }
+ mode = JS_strdup(cx, JS_GetStringBytes(strmode));
+ }else{
+ if(file->path[0]==PIPE_SYMBOL){
+ /* pipe default mode */
+ mode = JS_strdup(cx, "read");
+ }else
+ if(file->path[len-1]==PIPE_SYMBOL){
+ /* pipe default mode */
+ mode = JS_strdup(cx, "write");
+ }else{
+ /* non-destructive, permissive defaults. */
+ mode = JS_strdup(cx, "readWrite,append,create");
+ }
+ }
+
+ /* Process the mode */
+ mask = 0;
+ /* TODO: this is pretty ugly, BTW, we walk thru the string too many times */
+ mask|=(js_FileHasOption(cx, mode, "read"))? PR_RDONLY : 0;
+ mask|=(js_FileHasOption(cx, mode, "write"))? PR_WRONLY : 0;
+ mask|=(js_FileHasOption(cx, mode, "readWrite"))? PR_RDWR : 0;
+ mask|=(js_FileHasOption(cx, mode, "append"))? PR_APPEND : 0;
+ mask|=(js_FileHasOption(cx, mode, "create"))? PR_CREATE_FILE : 0;
+ mask|=(js_FileHasOption(cx, mode, "replace"))? PR_TRUNCATE : 0;
+
+ if((mask&PR_RDWR)) mask|=(PR_RDONLY|PR_WRONLY);
+ if((mask&PR_RDONLY)&&(mask&PR_WRONLY)) mask|=PR_RDWR;
+
+ file->hasAutoflush|=(js_FileHasOption(cx, mode, "autoflush"));
+
+ /* Type */
+ if (argc>1) {
+ strtype = JS_ValueToString(cx, argv[1]);
+ if (!strtype) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR, argv[1]);
+ goto out;
+ }
+ ctype = JS_GetStringBytes(strtype);
+
+ if(!strcmp(ctype, utfstring))
+ type = UTF8;
+ else
+ if (!strcmp(ctype, unicodestring))
+ type = UCS2;
+ else{
+ if(strcmp(ctype, asciistring)){
+ JS_ReportWarning(cx, "File type %s is not supported, using "
+ "'text' instead, proceeding", ctype);
+ }
+ type = ASCII;
+ }
+ }else{
+ type = ASCII;
+ }
+
+ /* Save the relevant fields */
+ file->type = type;
+ file->mode = mask;
+ file->nativehandle = NULL;
+ file->hasRandomAccess = (type!=UTF8);
+
+ /*
+ Deal with pipes here. We can't use NSPR for pipes,
+ so we have to use POPEN.
+ */
+ if(file->path[0]==PIPE_SYMBOL || file->path[len-1]==PIPE_SYMBOL){
+ if(file->path[0]==PIPE_SYMBOL && file->path[len-1]==PIPE_SYMBOL){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED);
+ goto out;
+ }else{
+ char pipemode[3];
+ SECURITY_CHECK(cx, NULL, "pipe_open", file);
+
+ if(file->path[0] == PIPE_SYMBOL){
+ if(mask & (PR_WRONLY | PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE)){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES,
+ mode, file->path);
+ goto out;
+ }
+ /* open(SPOOLER, "| cat -v | lpr -h 2>/dev/null") -- pipe for writing */
+ pipemode[0] = 'r';
+ pipemode[1] = file->type==UTF8?'b':'t';
+ pipemode[2] = '\0';
+ file->nativehandle = POPEN(&file->path[1], pipemode);
+ }else
+ if(file->path[len-1] == PIPE_SYMBOL){
+ char *command = JS_malloc(cx, len);
+
+ strncpy(command, file->path, len-1);
+ command[len-1] = '\0';
+ /* open(STATUS, "netstat -an 2>&1 |") */
+ pipemode[0] = 'w';
+ pipemode[1] = file->type==UTF8?'b':'t';
+ pipemode[2] = '\0';
+ file->nativehandle = POPEN(command, pipemode);
+ JS_free(cx, command);
+ }
+ /* set the flags */
+ file->isNative = JS_TRUE;
+ file->isPipe = JS_TRUE;
+ file->hasRandomAccess = JS_FALSE;
+ }
+ }else{
+ /* TODO: what about the permissions?? Java ignores the problem... */
+ file->handle = PR_Open(file->path, mask, 0644);
+ }
+
+ js_ResetBuffers(file);
+ JS_free(cx, mode);
+ mode = NULL;
+
+ /* Set the open flag and return result */
+ if (file->handle==NULL && file->nativehandle==NULL){
+ file->isOpen = JS_FALSE;
+
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "open", file->path);
+ goto out;
+ }else
+ goto good;
+good:
+ file->isOpen = JS_TRUE;
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+out:
+ if(mode) JS_free(cx, mode);
+ *rval = JSVAL_VOID;
+ return JS_FALSE;
+}
+
+static JSBool
+file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+
+ SECURITY_CHECK(cx, NULL, "close", file);
+
+ if(!file->isOpen){
+ JS_ReportWarning(cx, "File %s is not open, can't close it, proceeding",
+ file->path);
+ goto out;
+ }
+
+ if(!file->isPipe){
+ if(file->isNative){
+ JS_ReportWarning(cx, "Unable to close a native file, proceeding", file->path);
+ goto out;
+ }else{
+ if(file->handle && PR_Close(file->handle)){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "close", file->path);
+
+ goto out;
+ }
+ }
+ }else{
+ if(PCLOSE(file->nativehandle)==-1){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "pclose", file->path);
+ goto out;
+ }
+ }
+
+ js_ResetAttributes(file);
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+
+static JSBool
+file_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+
+ SECURITY_CHECK(cx, NULL, "remove", file);
+ JSFILE_CHECK_NATIVE("remove");
+ JSFILE_CHECK_CLOSED("remove");
+
+ if ((js_isDirectory(cx, file) ?
+ PR_RmDir(file->path) : PR_Delete(file->path))==PR_SUCCESS) {
+ js_ResetAttributes(file);
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+ } else {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "remove", file->path);
+ goto out;
+ }
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+/* Raw PR-based function. No text processing. Just raw data copying. */
+static JSBool
+file_copyTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ char *dest = NULL;
+ PRFileDesc *handle = NULL;
+ char *buffer;
+ jsval count, size;
+ JSBool fileInitiallyOpen=JS_FALSE;
+
+ SECURITY_CHECK(cx, NULL, "copyTo", file); /* may need a second argument!*/
+ JSFILE_CHECK_ONE_ARG("copyTo");
+ JSFILE_CHECK_NATIVE("copyTo");
+ /* remeber the state */
+ fileInitiallyOpen = file->isOpen;
+ JSFILE_CHECK_READ;
+
+ dest = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
+
+ /* make sure we are not reading a file open for writing */
+ if (file->isOpen && !js_canRead(cx, file)) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR, file->path);
+ goto out;
+ }
+
+ if (file->handle==NULL){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "open", file->path);
+ goto out;
+ }
+
+ handle = PR_Open(dest, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0644);
+
+ if(!handle){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "open", dest);
+ goto out;
+ }
+
+ if ((size=js_size(cx, file))==JSVAL_VOID) {
+ goto out;
+ }
+
+ buffer = JS_malloc(cx, size);
+
+ count = INT_TO_JSVAL(PR_Read(file->handle, buffer, size));
+
+ /* reading panic */
+ if (count!=size) {
+ JS_free(cx, buffer);
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_COPY_READ_ERROR, file->path);
+ goto out;
+ }
+
+ count = INT_TO_JSVAL(PR_Write(handle, buffer, JSVAL_TO_INT(size)));
+
+ /* writing panic */
+ if (count!=size) {
+ JS_free(cx, buffer);
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_COPY_WRITE_ERROR, file->path);
+ goto out;
+ }
+
+ JS_free(cx, buffer);
+
+ if(!fileInitiallyOpen){
+ if(!file_close(cx, obj, 0, NULL, rval)) goto out;
+ }
+
+ if(PR_Close(handle)!=PR_SUCCESS){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "close", dest);
+ goto out;
+ }
+
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+out:
+ if(file->isOpen && !fileInitiallyOpen){
+ if(PR_Close(file->handle)!=PR_SUCCESS){
+ JS_ReportWarning(cx, "Can't close %s, proceeding", file->path);
+ }
+ }
+
+ if(handle && PR_Close(handle)!=PR_SUCCESS){
+ JS_ReportWarning(cx, "Can't close %s, proceeding", dest);
+ }
+
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_renameTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ char *dest;
+
+ SECURITY_CHECK(cx, NULL, "renameTo", file); /* may need a second argument!*/
+ JSFILE_CHECK_ONE_ARG("renameTo");
+ JSFILE_CHECK_NATIVE("renameTo");
+ JSFILE_CHECK_CLOSED("renameTo");
+
+ dest = RESOLVE_PATH(cx, JS_GetStringBytes(JS_ValueToString(cx, argv[0])));
+
+ if (PR_Rename(file->path, dest)==PR_SUCCESS){
+ /* copy the new filename */
+ JS_free(cx, file->path);
+ file->path = dest;
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+ }else{
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_RENAME_FAILED, file->path, dest);
+ goto out;
+ }
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_flush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+
+ SECURITY_CHECK(cx, NULL, "flush", file);
+ JSFILE_CHECK_NATIVE("flush");
+ JSFILE_CHECK_OPEN("flush");
+
+ if (PR_Sync(file->handle)==PR_SUCCESS){
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+ }else{
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "flush", file->path);
+ goto out;
+ }
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ JSString *str;
+ int32 count;
+ uintN i;
+
+ SECURITY_CHECK(cx, NULL, "write", file);
+ JSFILE_CHECK_WRITE;
+
+ for (i = 0; i<argc; i++) {
+ str = JS_ValueToString(cx, argv[i]);
+ count = js_FileWrite(cx, file, JS_GetStringChars(str),
+ JS_GetStringLength(str), file->type);
+ if (count==-1){
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+ }
+ }
+
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ JSString *str;
+
+ SECURITY_CHECK(cx, NULL, "writeln", file);
+ JSFILE_CHECK_WRITE;
+
+ /* don't report an error here */
+ if(!file_write(cx, obj, argc, argv, rval)) return JS_FALSE;
+ /* don't do security here -- we passed the check in file_write */
+ str = JS_NewStringCopyZ(cx, "\n");
+
+ if (js_FileWrite(cx, file, JS_GetStringChars(str), JS_GetStringLength(str),
+ file->type)==-1){
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+ }
+
+ /* eol causes flush if hasAutoflush is turned on */
+ if (file->hasAutoflush)
+ file_flush(cx, obj, 0, NULL, rval);
+
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_writeAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ jsuint i;
+ jsuint limit;
+ JSObject *array;
+ JSObject *elem;
+ jsval elemval;
+
+ SECURITY_CHECK(cx, NULL, "writeAll", file);
+ JSFILE_CHECK_ONE_ARG("writeAll");
+ JSFILE_CHECK_WRITE;
+
+ if (!JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[0]))) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR);
+ goto out;
+ }
+
+ array = JSVAL_TO_OBJECT(argv[0]);
+
+ JS_GetArrayLength(cx, array, &limit);
+
+ for (i = 0; i<limit; i++) {
+ if (!JS_GetElement(cx, array, i, &elemval)) return JS_FALSE;
+ elem = JSVAL_TO_OBJECT(elemval);
+ file_writeln(cx, obj, 1, &elemval, rval);
+ }
+
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ JSString *str;
+ int32 want, count;
+ jschar *buf;
+
+ SECURITY_CHECK(cx, NULL, "read", file);
+ JSFILE_CHECK_ONE_ARG("read");
+ JSFILE_CHECK_READ;
+
+ if (!JS_ValueToInt32(cx, argv[0], &want)){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "read", argv[0]);
+ goto out;
+ }
+
+ /* want = (want>262144)?262144:want; * arbitrary size limitation */
+
+ buf = JS_malloc(cx, want*sizeof buf[0]);
+ if (!buf) goto out;
+
+ count = js_FileRead(cx, file, buf, want, file->type);
+ if (count>0) {
+ str = JS_NewUCStringCopyN(cx, buf, count);
+ *rval = STRING_TO_JSVAL(str);
+ JS_free(cx, buf);
+ return JS_TRUE;
+ } else {
+ JS_free(cx, buf);
+ goto out;
+ }
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ JSString *str;
+ jschar *buf;
+ int32 offset;
+ intN room;
+ jschar data, data2;
+ JSBool endofline;
+
+ SECURITY_CHECK(cx, NULL, "readln", file);
+ JSFILE_CHECK_READ;
+
+ if (!file->linebuffer) {
+ buf = JS_malloc(cx, MAX_LINE_LENGTH*(sizeof data));
+ if (!buf) goto out;
+ file->linebuffer = JS_NewUCString(cx, buf, MAX_LINE_LENGTH);
+ }
+ room = JS_GetStringLength(file->linebuffer);
+ offset = 0;
+
+ /* XXX TEST ME!! TODO: yes, please do */
+ for(;;) {
+ if (!js_FileRead(cx, file, &data, 1, file->type)) {
+ endofline = JS_FALSE;
+ goto loop;
+ }
+ switch (data) {
+ case '\n' :
+ endofline = JS_TRUE;
+ goto loop;
+ case '\r' :
+ if (!js_FileRead(cx, file, &data2, 1, file->type)) {
+ endofline = JS_TRUE;
+ goto loop;
+ }
+ if (data2!='\n') { /* We read one char too far. Buffer it. */
+ file->charBuffer = data2;
+ file->charBufferUsed = JS_TRUE;
+ }
+ endofline = JS_TRUE;
+ goto loop;
+ default:
+ if (--room < 0) {
+ buf = JS_malloc(cx, (offset+MAX_LINE_LENGTH)*sizeof data);
+ if (!buf) return JS_FALSE;
+ room = MAX_LINE_LENGTH-1;
+ memcpy(buf, JS_GetStringChars(file->linebuffer),
+ JS_GetStringLength(file->linebuffer));
+ /* what follows may not be the cleanest way. */
+ file->linebuffer->chars = buf;
+ file->linebuffer->length = offset+MAX_LINE_LENGTH;
+ }
+ file->linebuffer->chars[offset++] = data;
+ break;
+ }
+ }
+loop:
+ file->linebuffer->chars[offset] = 0;
+ if ((endofline==JS_TRUE)) {
+ str = JS_NewUCStringCopyN(cx, JS_GetStringChars(file->linebuffer),
+ offset);
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+ }else{
+ goto out;
+ }
+out:
+ *rval = JSVAL_NULL;
+ return JS_FALSE;
+}
+
+static JSBool
+file_readAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ JSObject *array;
+ jsint len;
+ jsval line;
+
+ SECURITY_CHECK(cx, NULL, "readAll", file);
+ JSFILE_CHECK_READ;
+
+ array = JS_NewArrayObject(cx, 0, NULL);
+ len = 0;
+
+ while(file_readln(cx, obj, 0, NULL, &line)){
+ JS_SetElement(cx, array, len, &line);
+ len++;
+ }
+
+ *rval = OBJECT_TO_JSVAL(array);
+ return JS_TRUE;
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_seek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ int32 toskip;
+ int32 pos;
+
+ SECURITY_CHECK(cx, NULL, "seek", file);
+ JSFILE_CHECK_ONE_ARG("seek");
+ JSFILE_CHECK_NATIVE("seek");
+ JSFILE_CHECK_READ;
+
+ if (!JS_ValueToInt32(cx, argv[0], &toskip)){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "seek", argv[0]);
+ goto out;
+ }
+
+ if(!file->hasRandomAccess){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_NO_RANDOM_ACCESS, file->path);
+ goto out;
+ }
+
+ if(js_isDirectory(cx, file)){
+ JS_ReportWarning(cx,"Seek on directories is not supported, proceeding");
+ goto out;
+ }
+
+ pos = js_FileSeek(cx, file, toskip, file->type);
+
+ if (pos!=-1) {
+ *rval = INT_TO_JSVAL(pos);
+ return JS_TRUE;
+ }
+out:
+ *rval = JSVAL_VOID;
+ return JS_FALSE;
+}
+
+static JSBool
+file_list(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ PRDir *dir;
+ PRDirEntry *entry;
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ JSObject *array;
+ JSObject *eachFile;
+ jsint len;
+ jsval v;
+ JSRegExp *re = NULL;
+ JSFunction *func = NULL;
+ JSString *str;
+ jsval args[1];
+ char *filePath;
+
+ SECURITY_CHECK(cx, NULL, "list", file);
+ JSFILE_CHECK_NATIVE("list");
+
+ if (argc==1) {
+ if (JSVAL_IS_REGEXP(cx, argv[0])) {
+ re = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
+ }else
+ if (JSVAL_IS_FUNCTION(cx, argv[0])) {
+ func = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
+ }else{
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, argv[0]);
+ goto out;
+ }
+ }
+
+ if (!js_isDirectory(cx, file)) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE, file->path);
+ goto out;
+ }
+
+ dir = PR_OpenDir(file->path);
+ if(!dir){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "open", file->path);
+ goto out;
+ }
+
+ /* create JSArray here... */
+ array = JS_NewArrayObject(cx, 0, NULL);
+ len = 0;
+
+ while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))!=NULL) {
+ /* first, check if we have a regexp */
+ if (re!=NULL) {
+ size_t index = 0;
+
+ str = JS_NewStringCopyZ(cx, entry->name);
+ if(!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &v)){
+ /* don't report anything here */
+ goto out;
+ }
+ /* not matched! */
+ if (JSVAL_IS_NULL(v)) {
+ continue;
+ }
+ }else
+ if (func!=NULL) {
+ str = JS_NewStringCopyZ(cx, entry->name);
+ args[0] = STRING_TO_JSVAL(str);
+ if(!JS_CallFunction(cx, obj, func, 1, args, &v)){
+ goto out;
+ }
+
+ if (v==JSVAL_FALSE) {
+ continue;
+ }
+ }
+
+ filePath = js_combinePath(cx, file->path, (char*)entry->name);
+
+ eachFile = js_NewFileObject(cx, filePath);
+ JS_free(cx, filePath);
+ if (!eachFile){
+ JS_ReportWarning(cx, "File %s cannot be retrieved", filePath);
+ continue;
+ }
+ v = OBJECT_TO_JSVAL(eachFile);
+ JS_SetElement(cx, array, len, &v);
+ JS_SetProperty(cx, array, entry->name, &v);
+ len++;
+ }
+
+ if(PR_CloseDir(dir)!=PR_SUCCESS){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "close", file->path);
+ goto out;
+ }
+ *rval = OBJECT_TO_JSVAL(array);
+ return JS_TRUE;
+out:
+ *rval = JSVAL_NULL;
+ return JS_FALSE;
+}
+
+static JSBool
+file_mkdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+
+ SECURITY_CHECK(cx, NULL, "mkdir", file);
+ JSFILE_CHECK_ONE_ARG("mkdir");
+ JSFILE_CHECK_NATIVE("mkdir");
+
+ /* if the current file is not a directory, find out the directory name */
+ if (!js_isDirectory(cx, file)) {
+ char *dir = js_fileDirectoryName(cx, file->path);
+ JSObject *dirObj = js_NewFileObject(cx, dir);
+
+ JS_free(cx, dir);
+
+ /* call file_mkdir with the right set of parameters if needed */
+ if (file_mkdir(cx, dirObj, argc, argv, rval))
+ return JS_TRUE;
+ else
+ goto out;
+ }else{
+ char *dirName = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
+ char *fullName;
+
+ fullName = js_combinePath(cx, file->path, dirName);
+ if (PR_MkDir(fullName, 0755)==PR_SUCCESS){
+ *rval = JSVAL_TRUE;
+ JS_free(cx, fullName);
+ return JS_TRUE;
+ }else{
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "mkdir", fullName);
+ JS_free(cx, fullName);
+ goto out;
+ }
+ }
+out:
+ *rval = JSVAL_FALSE;
+ return JS_FALSE;
+}
+
+static JSBool
+file_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval*rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+
+ *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, file->path));
+ return JS_TRUE;
+}
+
+static JSBool
+file_toURL(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ char url[MAX_PATH_LENGTH];
+ jschar *urlChars;
+
+ JSFILE_CHECK_NATIVE("toURL");
+
+ sprintf(url, "file://%s", file->path);
+ /* TODO: js_escape in jsstr.h may go away at some point */
+
+ urlChars = js_InflateString(cx, url, strlen(url));
+ if (urlChars == NULL) return JS_FALSE;
+ *rval = STRING_TO_JSVAL(js_NewString(cx, urlChars, strlen(url), 0));
+ if (!js_str_escape(cx, obj, 0, rval, rval)) return JS_FALSE;
+
+ return JS_TRUE;
+out:
+ *rval = JSVAL_VOID;
+ return JS_FALSE;
+}
+
+
+static void
+file_finalize(JSContext *cx, JSObject *obj)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+
+ if(file){
+ /* close the file before exiting */
+ if(file->isOpen && !file->isNative){
+ jsval vp;
+ file_close(cx, obj, 0, NULL, &vp);
+ }
+
+ if (file->path)
+ JS_free(cx, file->path);
+
+ JS_free(cx, file);
+ }
+}
+
+/*
+ Allocates memory for the file object, sets fields to defaults.
+*/
+static JSFile*
+file_init(JSContext *cx, JSObject *obj, char *bytes)
+{
+ JSFile *file;
+
+ file = JS_malloc(cx, sizeof *file);
+ if (!file) return NULL;
+ memset(file, 0 , sizeof *file);
+
+ js_ResetAttributes(file);
+
+ file->path = RESOLVE_PATH(cx, bytes);
+
+ if (!JS_SetPrivate(cx, obj, file)) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_SET_PRIVATE_FILE, file->path);
+ JS_free(cx, file);
+ return NULL;
+ }else
+ return file;
+}
+
+/* Returns a JSObject. This function is globally visible */
+JS_PUBLIC_API(JSObject*)
+js_NewFileObject(JSContext *cx, char *filename)
+{
+ JSObject *obj;
+ JSFile *file;
+
+ obj = JS_NewObject(cx, &file_class, NULL, NULL);
+ if (!obj){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObject");
+ return NULL;
+ }
+ file = file_init(cx, obj, filename);
+ if(!file) return NULL;
+ return obj;
+}
+
+/* Internal function, used for cases which NSPR file support doesn't cover */
+JSObject*
+js_NewFileObjectFromFILE(JSContext *cx, FILE *nativehandle, char *filename,
+ int32 mode, JSBool open, JSBool randomAccess)
+{
+ JSObject *obj;
+ JSFile *file;
+#ifdef XP_MAC
+ JS_ReportWarning(cx, "Native files are not fully supported on the MAC");
+#endif
+
+ obj = JS_NewObject(cx, &file_class, NULL, NULL);
+ if (!obj){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObjectFromFILE");
+ return NULL;
+ }
+ file = file_init(cx, obj, filename);
+ if(!file) return NULL;
+
+ file->nativehandle = nativehandle;
+
+ /* free result of RESOLVE_PATH from file_init. */
+ JS_ASSERT(file->path != NULL);
+ JS_free(cx, file->path);
+
+ file->path = strdup(filename);
+ file->isOpen = open;
+ file->mode = mode;
+ file->hasRandomAccess = randomAccess;
+ file->isNative = JS_TRUE;
+ return obj;
+}
+
+/*
+ Real file constructor that is called from JavaScript.
+ Basically, does error processing and calls file_init.
+*/
+static JSBool
+file_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+ JSFile *file;
+
+ str = (argc==0)?JS_InternString(cx, ""):JS_ValueToString(cx, argv[0]);
+
+ if (!str){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR, argv[0]);
+ goto out;
+ }
+
+ file = file_init(cx, obj, JS_GetStringBytes(str));
+ if (!file) goto out;
+
+ SECURITY_CHECK(cx, NULL, "constructor", file);
+
+ return JS_TRUE;
+out:
+ *rval = JSVAL_VOID;
+ return JS_FALSE;
+}
+
+/* -------------------- File methods and properties ------------------------- */
+static JSFunctionSpec file_functions[] = {
+ { "open", file_open, 0},
+ { "close", file_close, 0},
+ { "remove", file_remove, 0},
+ { "copyTo", file_copyTo, 0},
+ { "renameTo", file_renameTo, 0},
+ { "flush", file_flush, 0},
+ { "seek", file_seek, 0},
+ { "read", file_read, 0},
+ { "readln", file_readln, 0},
+ { "readAll", file_readAll, 0},
+ { "write", file_write, 0},
+ { "writeln", file_writeln, 0},
+ { "writeAll", file_writeAll, 0},
+ { "list", file_list, 0},
+ { "mkdir", file_mkdir, 0},
+ { "toString", file_toString, 0},
+ { "toURL", file_toURL, 0},
+ {0}
+};
+
+enum file_tinyid {
+ FILE_LENGTH = -2,
+ FILE_PARENT = -3,
+ FILE_PATH = -4,
+ FILE_NAME = -5,
+ FILE_ISDIR = -6,
+ FILE_ISFILE = -7,
+ FILE_EXISTS = -8,
+ FILE_CANREAD = -9,
+ FILE_CANWRITE = -10,
+ FILE_OPEN = -11,
+ FILE_TYPE = -12,
+ FILE_MODE = -13,
+ FILE_CREATED = -14,
+ FILE_MODIFIED = -15,
+ FILE_SIZE = -16,
+ FILE_RANDOMACCESS = -17,
+ FILE_POSITION = -18,
+ FILE_APPEND = -19,
+ FILE_REPLACE = -20,
+ FILE_AUTOFLUSH = -21,
+ FILE_ISNATIVE = -22,
+};
+
+static JSPropertySpec file_props[] = {
+ {"length", FILE_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"parent", FILE_PARENT, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"path", FILE_PATH, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"name", FILE_NAME, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"isDirectory", FILE_ISDIR, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"isFile", FILE_ISFILE, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"exists", FILE_EXISTS, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"canRead", FILE_CANREAD, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"canWrite", FILE_CANWRITE, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"canAppend", FILE_APPEND, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"canReplace", FILE_REPLACE, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"isOpen", FILE_OPEN, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"type", FILE_TYPE, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"mode", FILE_MODE, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"creationTime", FILE_CREATED, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"lastModified", FILE_MODIFIED, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"size", FILE_SIZE, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"hasRandomAccess", FILE_RANDOMACCESS, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"hasAutoFlush", FILE_AUTOFLUSH, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {"position", FILE_POSITION, JSPROP_ENUMERATE },
+ {"isNative", FILE_ISNATIVE, JSPROP_ENUMERATE | JSPROP_READONLY },
+ {0}
+};
+
+/* ------------------------- Property getter/setter ------------------------- */
+static JSBool
+file_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ char *str;
+ jsint tiny;
+ PRFileInfo info;
+ JSBool flag;
+ PRExplodedTime
+ expandedTime;
+
+ tiny = JSVAL_TO_INT(id);
+ if(!file) return JS_TRUE;
+
+ switch (tiny) {
+ case FILE_PARENT:
+ SECURITY_CHECK(cx, NULL, "parent", file);
+ *vp = js_parent(cx, file);
+ break;
+ case FILE_PATH:
+ *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, file->path));
+ break;
+ case FILE_NAME:
+ *vp = js_name(cx, file);
+ break;
+ case FILE_ISDIR:
+ SECURITY_CHECK(cx, NULL, "isDirectory", file);
+ *vp = BOOLEAN_TO_JSVAL(js_isDirectory(cx, file));
+ break;
+ case FILE_ISFILE:
+ SECURITY_CHECK(cx, NULL, "isFile", file);
+ *vp = BOOLEAN_TO_JSVAL(js_isFile(cx, file));
+ break;
+ case FILE_EXISTS:
+ SECURITY_CHECK(cx, NULL, "exists", file);
+ *vp = BOOLEAN_TO_JSVAL(js_exists(cx, file));
+ break;
+ case FILE_ISNATIVE:
+ SECURITY_CHECK(cx, NULL, "isNative", file);
+ *vp = BOOLEAN_TO_JSVAL(file->isNative);
+ break;
+ case FILE_CANREAD:
+ SECURITY_CHECK(cx, NULL, "canRead", file);
+ *vp = BOOLEAN_TO_JSVAL(js_canRead(cx, file));
+ break;
+ case FILE_CANWRITE:
+ SECURITY_CHECK(cx, NULL, "canWrite", file);
+ *vp = BOOLEAN_TO_JSVAL(js_canWrite(cx, file));
+ break;
+ case FILE_OPEN:
+ SECURITY_CHECK(cx, NULL, "isOpen", file);
+ *vp = BOOLEAN_TO_JSVAL(file->isOpen);
+ break;
+ case FILE_APPEND :
+ SECURITY_CHECK(cx, NULL, "canAppend", file);
+ JSFILE_CHECK_OPEN("canAppend");
+ *vp = BOOLEAN_TO_JSVAL(!file->isNative &&
+ (file->mode&PR_APPEND)==PR_APPEND);
+ break;
+ case FILE_REPLACE :
+ SECURITY_CHECK(cx, NULL, "canReplace", file);
+ JSFILE_CHECK_OPEN("canReplace");
+ *vp = BOOLEAN_TO_JSVAL(!file->isNative &&
+ (file->mode&PR_TRUNCATE)==PR_TRUNCATE);
+ break;
+ case FILE_AUTOFLUSH :
+ SECURITY_CHECK(cx, NULL, "hasAutoFlush", file);
+ JSFILE_CHECK_OPEN("hasAutoFlush");
+ *vp = BOOLEAN_TO_JSVAL(!file->isNative && file->hasAutoflush);
+ break;
+ case FILE_TYPE:
+ SECURITY_CHECK(cx, NULL, "type", file);
+ JSFILE_CHECK_OPEN("type");
+ if(js_isDirectory(cx, file)){
+ *vp = JSVAL_VOID;
+ break;
+ }
+
+ switch (file->type) {
+ case ASCII:
+ *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, asciistring));
+ break;
+ case UTF8:
+ *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, utfstring));
+ break;
+ case UCS2:
+ *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, unicodestring));
+ break;
+ default:
+ JS_ReportWarning(cx, "Unsupported file type %d, proceeding",
+ file->type);
+ }
+ break;
+ case FILE_MODE:
+ SECURITY_CHECK(cx, NULL, "mode", file);
+ JSFILE_CHECK_OPEN("mode");
+ str = (char*)JS_malloc(cx, MODE_SIZE);
+ str[0] = '\0';
+ flag = JS_FALSE;
+
+ if ((file->mode&PR_RDONLY)==PR_RDONLY) {
+ if (flag) strcat(str, ",");
+ strcat(str, "read");
+ flag = JS_TRUE;
+ }
+ if ((file->mode&PR_WRONLY)==PR_WRONLY) {
+ if (flag) strcat(str, ",");
+ strcat(str, "write");
+ flag = JS_TRUE;
+ }
+ if ((file->mode&PR_RDWR)==PR_RDWR) {
+ if (flag) strcat(str, ",");
+ strcat(str, "readWrite");
+ flag = JS_TRUE;
+ }
+ if ((file->mode&PR_APPEND)==PR_APPEND) {
+ if (flag) strcat(str, ",");
+ strcat(str, "append");
+ flag = JS_TRUE;
+ }
+ if ((file->mode&PR_CREATE_FILE)==PR_CREATE_FILE) {
+ if (flag) strcat(str, ",");
+ strcat(str, "create");
+ flag = JS_TRUE;
+ }
+ if ((file->mode&PR_TRUNCATE)==PR_TRUNCATE) {
+ if (flag) strcat(str, ",");
+ strcat(str, "replace");
+ flag = JS_TRUE;
+ }
+ if (file->hasAutoflush) {
+ if (flag) strcat(str, ",");
+ strcat(str, "hasAutoFlush");
+ flag = JS_TRUE;
+ }
+ *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str));
+ JS_free(cx, str);
+ break;
+ case FILE_CREATED:
+ SECURITY_CHECK(cx, NULL, "creationTime", file);
+ JSFILE_CHECK_NATIVE("creationTime");
+ if(((file->isOpen)?
+ PR_GetOpenFileInfo(file->handle, &info):
+ PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
+ goto out;
+ }
+
+ PR_ExplodeTime(info.creationTime, PR_LocalTimeParameters,&expandedTime);
+ *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year,
+ expandedTime.tm_month,
+ expandedTime.tm_mday,
+ expandedTime.tm_hour,
+ expandedTime.tm_min,
+ expandedTime.tm_sec));
+ break;
+ case FILE_MODIFIED:
+ SECURITY_CHECK(cx, NULL, "lastModified", file);
+ JSFILE_CHECK_NATIVE("lastModified");
+ if(((file->isOpen)?
+ PR_GetOpenFileInfo(file->handle, &info):
+ PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
+ goto out;
+ }
+
+ PR_ExplodeTime(info.modifyTime, PR_LocalTimeParameters, &expandedTime);
+ *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year,
+ expandedTime.tm_month,
+ expandedTime.tm_mday,
+ expandedTime.tm_hour,
+ expandedTime.tm_min,
+ expandedTime.tm_sec));
+ break;
+ case FILE_SIZE:
+ SECURITY_CHECK(cx, NULL, "size", file);
+ *vp = js_size(cx, file);
+ break;
+ case FILE_LENGTH:
+ SECURITY_CHECK(cx, NULL, "length", file);
+ JSFILE_CHECK_NATIVE("length");
+
+ if (js_isDirectory(cx, file)) { /* XXX debug me */
+ PRDir *dir;
+ PRDirEntry *entry;
+ jsint count = 0;
+
+ if(!(dir = PR_OpenDir(file->path))){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_OPEN_DIR, file->path);
+ goto out;
+ }
+
+ while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))) {
+ count++;
+ }
+
+ if(!PR_CloseDir(dir)){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_OP_FAILED, "close", file->path);
+
+ goto out;
+ }
+
+ *vp = INT_TO_JSVAL(count);
+ break;
+ }else{
+ /* return file size */
+ *vp = js_size(cx, file);
+ }
+ break;
+ case FILE_RANDOMACCESS:
+ SECURITY_CHECK(cx, NULL, "hasRandomAccess", file);
+ JSFILE_CHECK_OPEN("hasRandomAccess");
+ *vp = BOOLEAN_TO_JSVAL(file->hasRandomAccess);
+ break;
+ case FILE_POSITION:
+ SECURITY_CHECK(cx, NULL, "position", file);
+ JSFILE_CHECK_NATIVE("position");
+ JSFILE_CHECK_OPEN("position");
+
+ if(!file->hasRandomAccess){
+ JS_ReportWarning(cx, "File %s doesn't support random access, can't report the position, proceeding");
+ *vp = JSVAL_VOID;
+ break;
+ }
+
+ if (file->isOpen && js_isFile(cx, file)) {
+ int pos = PR_Seek(file->handle, 0, PR_SEEK_CUR);
+ if(pos!=-1){
+ *vp = INT_TO_JSVAL(pos);
+ }else{
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_REPORT_POSITION, file->path);
+ goto out;
+ }
+ }else {
+ JS_ReportWarning(cx, "File %s is closed or not a plain file,"
+ " can't report position, proceeding");
+ goto out;
+ }
+ break;
+ default:
+ SECURITY_CHECK(cx, NULL, "file_access", file);
+ /* this is some other property -- try to use the dir["file"] syntax */
+ if(js_isDirectory(cx, file)){
+ PRDir *dir = NULL;
+ PRDirEntry *entry = NULL;
+ char *prop_name = JS_GetStringBytes(JS_ValueToString(cx, id));
+
+ /* no native files past this point */
+ dir = PR_OpenDir(file->path);
+ if(!dir) {
+ /* This is probably not a directory */
+ JS_ReportWarning(cx, "Can't open directory %s", file->path);
+ return JS_FALSE;
+ }
+
+ while((entry = PR_ReadDir(dir, PR_SKIP_NONE))!=NULL){
+ if(!strcmp(entry->name, prop_name)){
+ str = js_combinePath(cx, file->path, prop_name);
+ *vp = OBJECT_TO_JSVAL(js_NewFileObject(cx, str));
+ JS_free(cx, str);
+ return JS_TRUE;
+ }
+ }
+ }
+ }
+ return JS_TRUE;
+out:
+ *vp = JSVAL_VOID;
+ return JS_FALSE;
+}
+
+static JSBool
+file_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSFile *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
+ jsint slot;
+
+ if (JSVAL_IS_STRING(id)){
+ return JS_TRUE;
+ }
+
+ slot = JSVAL_TO_INT(id);
+
+ switch (slot) {
+ /* File.position = 10 */
+ case FILE_POSITION:
+ SECURITY_CHECK(cx, NULL, "set_position", file);
+ JSFILE_CHECK_NATIVE("set_position");
+
+ if(!file->hasRandomAccess){
+ JS_ReportWarning(cx, "File %s doesn't support random access, can't "
+ "report the position, proceeding");
+ goto out;
+ }
+
+ if (file->isOpen && js_isFile(cx, file)) {
+ int32 pos;
+ int32 offset;
+
+ if (!JS_ValueToInt32(cx, *vp, &offset)){
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "position", *vp);
+ goto out;
+ }
+
+ pos = PR_Seek(file->handle, offset, PR_SEEK_SET);
+
+ if(pos!=-1){
+ *vp = INT_TO_JSVAL(pos);
+ }else{
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_CANNOT_SET_POSITION, file->path);
+ goto out;
+ }
+ } else {
+ JS_ReportWarning(cx, "File %s is closed or not a file, can't set "
+ "position, proceeding", file->path);
+ goto out;
+ }
+ }
+
+ return JS_TRUE;
+out:
+ *vp = JSVAL_VOID;
+ return JS_FALSE;
+}
+
+/*
+ File.currentDir = new File("D:\") or File.currentDir = "D:\"
+*/
+static JSBool
+file_currentDirSetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSObject *rhsObject;
+ char *path;
+ JSFile *file = JS_GetInstancePrivate(cx, rhsObject, &file_class, NULL);
+
+ /* Look at the rhs and extract a file object from it */
+ if (JSVAL_IS_OBJECT(*vp)){
+ if (JS_InstanceOf(cx, rhsObject, &file_class, NULL)){
+ /* Braindamaged rhs -- just return the old value */
+ if (file && (!js_exists(cx, file) || !js_isDirectory(cx, file))){
+ JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, vp);
+ goto out;
+ }else{
+ rhsObject = JSVAL_TO_OBJECT(*vp);
+ chdir(file->path);
+ return JS_TRUE;
+ }
+ }else
+ goto out;
+ }else{
+ path = JS_GetStringBytes(JS_ValueToString(cx, *vp));
+ rhsObject = js_NewFileObject(cx, path);
+ if (!rhsObject) goto out;
+
+ if (!file || !js_exists(cx, file) || !js_isDirectory(cx, file)){
+ JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, vp);
+ }else{
+ *vp = OBJECT_TO_JSVAL(rhsObject);
+ chdir(path);
+ }
+ }
+ return JS_TRUE;
+out:
+ *vp = JSVAL_VOID;
+ return JS_FALSE;
+}
+
+/* Declare class */
+static JSClass file_class = {
+ FILE_CONSTRUCTOR, JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, file_getProperty, file_setProperty,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, file_finalize
+};
+
+/* -------------------- Functions exposed to the outside -------------------- */
+JS_PUBLIC_API(JSObject*)
+js_InitFileClass(JSContext *cx, JSObject* obj, JSBool initStandardStreams)
+{
+ JSObject *file, *ctor, *afile;
+ jsval vp;
+ char *currentdir;
+ char separator[2];
+
+ file = JS_InitClass(cx, obj, NULL, &file_class, file_constructor, 1,
+ file_props, file_functions, NULL, NULL);
+ if (!file) {
+ JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
+ JSFILEMSG_INIT_FAILED);
+ return NULL;
+ }
+
+ ctor = JS_GetConstructor(cx, file);
+ if (!ctor) return NULL;
+
+ /* Define CURRENTDIR property. We are doing this to get a
+ slash at the end of the current dir */
+ afile = js_NewFileObject(cx, CURRENT_DIR);
+ currentdir = JS_malloc(cx, MAX_PATH_LENGTH);
+ currentdir = getcwd(currentdir, MAX_PATH_LENGTH);
+ afile = js_NewFileObject(cx, currentdir);
+ JS_free(cx, currentdir);
+ vp = OBJECT_TO_JSVAL(afile);
+ JS_DefinePropertyWithTinyId(cx, ctor, CURRENTDIR_PROPERTY, 0, vp,
+ JS_PropertyStub, file_currentDirSetter,
+ JSPROP_ENUMERATE | JSPROP_READONLY );
+
+ if(initStandardStreams){
+ /* Code to create stdin, stdout, and stderr. Insert in the appropriate place. */
+ /* Define input */
+ vp = OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx, stdin,
+ STDINPUT_NAME, PR_RDONLY, JS_TRUE, JS_FALSE));
+ JS_SetProperty(cx, ctor, "input", &vp);
+
+ /* Define output */
+ vp = OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx, stdout,
+ STDOUTPUT_NAME, PR_WRONLY, JS_TRUE, JS_FALSE));
+ JS_SetProperty(cx, ctor, "output", &vp);
+
+ /* Define error */
+ vp = OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx, stderr,
+ STDERROR_NAME, PR_WRONLY, JS_TRUE, JS_FALSE));
+ JS_SetProperty(cx, ctor, "error", &vp);
+ }
+ separator[0] = FILESEPARATOR;
+ separator[1] = '\0';
+ vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, separator));
+ JS_DefinePropertyWithTinyId(cx, ctor, SEPARATOR_PROPERTY, 0, vp,
+ JS_PropertyStub, JS_PropertyStub,
+ JSPROP_ENUMERATE | JSPROP_READONLY );
+ return file;
+}
+#endif /* JS_HAS_FILE_OBJECT */
diff --git a/src/dom/js/jsfile.h b/src/dom/js/jsfile.h
new file mode 100644
index 000000000..47a8692d8
--- /dev/null
+++ b/src/dom/js/jsfile.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _jsfile_h__
+#define _jsfile_h__
+
+#if JS_HAS_FILE_OBJECT
+extern JS_PUBLIC_API(JSObject*)
+js_InitFileClass(JSContext *cx, JSObject* obj, JSBool initStandardStreams);
+
+extern JS_PUBLIC_API(JSObject*)
+js_NewFileObject(JSContext *cx, char *bytes);
+#endif /* JS_HAS_FILE_OBJECT */
+#endif /* _jsfile_h__ */
diff --git a/src/dom/js/jsfun.c b/src/dom/js/jsfun.c
new file mode 100644
index 000000000..93cd4009d
--- /dev/null
+++ b/src/dom/js/jsfun.c
@@ -0,0 +1,2059 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS function support.
+ */
+#include "jsstddef.h"
+#include <string.h>
+#include "jstypes.h"
+#include "jsbit.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdbgapi.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsparse.h"
+#include "jsscan.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+#include "jsexn.h"
+
+/* Generic function/call/arguments tinyids -- also reflected bit numbers. */
+enum {
+ CALL_ARGUMENTS = -1, /* predefined arguments local variable */
+ CALL_CALLEE = -2, /* reference to active function's object */
+ ARGS_LENGTH = -3, /* number of actual args, arity if inactive */
+ ARGS_CALLEE = -4, /* reference from arguments to active funobj */
+ FUN_ARITY = -5, /* number of formal parameters; desired argc */
+ FUN_NAME = -6, /* function name, "" if anonymous */
+ FUN_CALLER = -7 /* Function.prototype.caller, backward compat */
+};
+
+#if JSFRAME_OVERRIDE_BITS < 8
+# error "not enough override bits in JSStackFrame.flags!"
+#endif
+
+#define TEST_OVERRIDE_BIT(fp, tinyid) \
+ ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
+
+#define SET_OVERRIDE_BIT(fp, tinyid) \
+ ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
+
+#if JS_HAS_ARGS_OBJECT
+
+JSBool
+js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp)
+{
+ JSObject *argsobj;
+
+ if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
+ JS_ASSERT(fp->callobj);
+ return OBJ_GET_PROPERTY(cx, fp->callobj,
+ (jsid) cx->runtime->atomState.argumentsAtom,
+ vp);
+ }
+ argsobj = js_GetArgsObject(cx, fp);
+ if (!argsobj)
+ return JS_FALSE;
+ *vp = OBJECT_TO_JSVAL(argsobj);
+ return JS_TRUE;
+}
+
+static JSBool
+MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
+{
+ JSObject *argsobj;
+ jsval bmapval, bmapint;
+ size_t nbits, nbytes;
+ jsbitmap *bitmap;
+
+ argsobj = fp->argsobj;
+ (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
+ nbits = JS_MAX(fp->argc, fp->fun->nargs);
+ JS_ASSERT(slot < nbits);
+ if (JSVAL_IS_VOID(bmapval)) {
+ if (nbits <= JSVAL_INT_BITS) {
+ bmapint = 0;
+ bitmap = (jsbitmap *) &bmapint;
+ } else {
+ nbytes = JS_HOWMANY(nbits, JS_BITS_PER_WORD) * sizeof(jsbitmap);
+ bitmap = (jsbitmap *) JS_malloc(cx, nbytes);
+ if (!bitmap)
+ return JS_FALSE;
+ memset(bitmap, 0, nbytes);
+ bmapval = PRIVATE_TO_JSVAL(bitmap);
+ JS_SetReservedSlot(cx, argsobj, 0, bmapval);
+ }
+ } else {
+ if (nbits <= JSVAL_INT_BITS) {
+ bmapint = JSVAL_TO_INT(bmapval);
+ bitmap = (jsbitmap *) &bmapint;
+ } else {
+ bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
+ }
+ }
+ JS_SET_BIT(bitmap, slot);
+ if (bitmap == (jsbitmap *) &bmapint) {
+ bmapval = INT_TO_JSVAL(bmapint);
+ JS_SetReservedSlot(cx, argsobj, 0, bmapval);
+ }
+ return JS_TRUE;
+}
+
+/* NB: Infallible predicate, false does not mean error/exception. */
+static JSBool
+ArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
+{
+ JSObject *argsobj;
+ jsval bmapval, bmapint;
+ jsbitmap *bitmap;
+
+ argsobj = fp->argsobj;
+ (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
+ if (JSVAL_IS_VOID(bmapval))
+ return JS_FALSE;
+ if (JS_MAX(fp->argc, fp->fun->nargs) <= JSVAL_INT_BITS) {
+ bmapint = JSVAL_TO_INT(bmapval);
+ bitmap = (jsbitmap *) &bmapint;
+ } else {
+ bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
+ }
+ return JS_TEST_BIT(bitmap, slot) != 0;
+}
+
+JSBool
+js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id,
+ JSObject **objp, jsval *vp)
+{
+ jsval val;
+ JSObject *obj;
+ uintN slot;
+
+ if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
+ JS_ASSERT(fp->callobj);
+ if (!OBJ_GET_PROPERTY(cx, fp->callobj,
+ (jsid) cx->runtime->atomState.argumentsAtom,
+ &val)) {
+ return JS_FALSE;
+ }
+ if (JSVAL_IS_PRIMITIVE(val)) {
+ obj = js_ValueToNonNullObject(cx, val);
+ if (!obj)
+ return JS_FALSE;
+ } else {
+ obj = JSVAL_TO_OBJECT(val);
+ }
+ *objp = obj;
+ return OBJ_GET_PROPERTY(cx, obj, id, vp);
+ }
+
+ *objp = NULL;
+ *vp = JSVAL_VOID;
+ if (JSVAL_IS_INT(id)) {
+ slot = (uintN) JSVAL_TO_INT(id);
+ if (slot < JS_MAX(fp->argc, fp->fun->nargs)) {
+ if (fp->argsobj && ArgWasDeleted(cx, fp, slot))
+ return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
+ *vp = fp->argv[slot];
+ }
+ } else {
+ if (id == (jsid) cx->runtime->atomState.lengthAtom) {
+ if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH))
+ return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
+ *vp = INT_TO_JSVAL((jsint) fp->argc);
+ }
+ }
+ return JS_TRUE;
+}
+
+JSObject *
+js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
+{
+ JSObject *argsobj;
+
+ /* Create an arguments object for fp only if it lacks one. */
+ JS_ASSERT(fp->fun);
+ argsobj = fp->argsobj;
+ if (argsobj)
+ return argsobj;
+
+ /* Link the new object to fp so it can get actual argument values. */
+ argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL);
+ if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ fp->argsobj = argsobj;
+ return argsobj;
+}
+
+static JSBool
+args_enumerate(JSContext *cx, JSObject *obj);
+
+JSBool
+js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
+{
+ JSObject *argsobj;
+ jsval bmapval, rval;
+ JSBool ok;
+ JSRuntime *rt;
+
+ /*
+ * Reuse args_enumerate here to reflect fp's actual arguments as indexed
+ * elements of argsobj. Do this first, before clearing and freeing the
+ * deleted argument slot bitmap, because args_enumerate depends on that.
+ */
+ argsobj = fp->argsobj;
+ ok = args_enumerate(cx, argsobj);
+
+ /*
+ * Now clear the deleted argument number bitmap slot and free the bitmap,
+ * if one was actually created due to 'delete arguments[0]' or similar.
+ */
+ (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
+ if (!JSVAL_IS_VOID(bmapval)) {
+ JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID);
+ if (JS_MAX(fp->argc, fp->fun->nargs) > JSVAL_INT_BITS)
+ JS_free(cx, JSVAL_TO_PRIVATE(bmapval));
+ }
+
+ /*
+ * Now get the prototype properties so we snapshot fp->fun and fp->argc
+ * before fp goes away.
+ */
+ rt = cx->runtime;
+ ok &= js_GetProperty(cx, argsobj, (jsid)rt->atomState.calleeAtom, &rval);
+ ok &= js_SetProperty(cx, argsobj, (jsid)rt->atomState.calleeAtom, &rval);
+ ok &= js_GetProperty(cx, argsobj, (jsid)rt->atomState.lengthAtom, &rval);
+ ok &= js_SetProperty(cx, argsobj, (jsid)rt->atomState.lengthAtom, &rval);
+
+ /*
+ * Clear the private pointer to fp, which is about to go away (js_Invoke).
+ * Do this last because the args_enumerate and js_GetProperty calls above
+ * need to follow the private slot to find fp.
+ */
+ ok &= JS_SetPrivate(cx, argsobj, NULL);
+ fp->argsobj = NULL;
+ return ok;
+}
+
+static JSBool
+args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsint slot;
+ JSStackFrame *fp;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ fp = (JSStackFrame *)
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->argsobj);
+ JS_ASSERT(fp->fun);
+
+ slot = JSVAL_TO_INT(id);
+ switch (slot) {
+ case ARGS_CALLEE:
+ case ARGS_LENGTH:
+ SET_OVERRIDE_BIT(fp, slot);
+ break;
+
+ default:
+ if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs) &&
+ !MarkArgDeleted(cx, fp, slot)) {
+ return JS_FALSE;
+ }
+ break;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsint slot;
+ JSStackFrame *fp;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ fp = (JSStackFrame *)
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->argsobj);
+ JS_ASSERT(fp->fun);
+
+ slot = JSVAL_TO_INT(id);
+ switch (slot) {
+ case ARGS_CALLEE:
+ if (!TEST_OVERRIDE_BIT(fp, slot))
+ *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
+ break;
+
+ case ARGS_LENGTH:
+ if (!TEST_OVERRIDE_BIT(fp, slot))
+ *vp = INT_TO_JSVAL((jsint)fp->argc);
+ break;
+
+ default:
+ if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs) &&
+ !ArgWasDeleted(cx, fp, slot)) {
+ *vp = fp->argv[slot];
+ }
+ break;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSStackFrame *fp;
+ jsint slot;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ fp = (JSStackFrame *)
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->argsobj);
+ JS_ASSERT(fp->fun);
+
+ slot = JSVAL_TO_INT(id);
+ switch (slot) {
+ case ARGS_CALLEE:
+ case ARGS_LENGTH:
+ SET_OVERRIDE_BIT(fp, slot);
+ break;
+
+ default:
+ if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs) &&
+ !ArgWasDeleted(cx, fp, slot)) {
+ fp->argv[slot] = *vp;
+ }
+ break;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
+ JSObject **objp)
+{
+ JSStackFrame *fp;
+ uintN slot;
+ JSString *str;
+ JSAtom *atom;
+ intN tinyid;
+ jsval value;
+
+ *objp = NULL;
+ fp = (JSStackFrame *)
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->argsobj);
+ JS_ASSERT(fp->fun);
+
+ if (JSVAL_IS_INT(id)) {
+ slot = JSVAL_TO_INT(id);
+ if (slot < JS_MAX(fp->argc, fp->fun->nargs) &&
+ !ArgWasDeleted(cx, fp, slot)) {
+ /* XXX ECMA specs DontEnum, contrary to other array-like objects */
+ if (!js_DefineProperty(cx, obj, (jsid) id, fp->argv[slot],
+ args_getProperty, args_setProperty,
+ JSVERSION_IS_ECMA(cx->version)
+ ? 0
+ : JSPROP_ENUMERATE,
+ NULL)) {
+ return JS_FALSE;
+ }
+ *objp = obj;
+ }
+ } else {
+ str = JSVAL_TO_STRING(id);
+ atom = cx->runtime->atomState.lengthAtom;
+ if (str == ATOM_TO_STRING(atom)) {
+ tinyid = ARGS_LENGTH;
+ value = INT_TO_JSVAL(fp->argc);
+ } else {
+ atom = cx->runtime->atomState.calleeAtom;
+ if (str == ATOM_TO_STRING(atom)) {
+ tinyid = ARGS_CALLEE;
+ value = fp->argv ? fp->argv[-2]
+ : OBJECT_TO_JSVAL(fp->fun->object);
+ } else {
+ atom = NULL;
+
+ /* Quell GCC overwarnings. */
+ tinyid = 0;
+ value = JSVAL_NULL;
+ }
+ }
+
+ if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
+ if (!js_DefineNativeProperty(cx, obj, (jsid) atom, value,
+ args_getProperty, args_setProperty, 0,
+ SPROP_HAS_SHORTID, tinyid, NULL)) {
+ return JS_FALSE;
+ }
+ *objp = obj;
+ }
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+args_enumerate(JSContext *cx, JSObject *obj)
+{
+ JSStackFrame *fp;
+ JSObject *pobj;
+ JSProperty *prop;
+ uintN slot, nargs;
+
+ fp = (JSStackFrame *)
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->argsobj);
+ JS_ASSERT(fp->fun);
+
+ /*
+ * Trigger reflection with value snapshot in args_resolve using a series
+ * of js_LookupProperty calls. We handle length, callee, and the indexed
+ * argument properties. We know that args_resolve covers all these cases
+ * and creates direct properties of obj, but that it may fail to resolve
+ * length or callee if overridden.
+ */
+ if (!js_LookupProperty(cx, obj, (jsid) cx->runtime->atomState.lengthAtom,
+ &pobj, &prop)) {
+ return JS_FALSE;
+ }
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+
+ if (!js_LookupProperty(cx, obj, (jsid) cx->runtime->atomState.calleeAtom,
+ &pobj, &prop)) {
+ return JS_FALSE;
+ }
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+
+ nargs = JS_MAX(fp->argc, fp->fun->nargs);
+ for (slot = 0; slot < nargs; slot++) {
+ if (!js_LookupProperty(cx, obj, (jsid) INT_TO_JSVAL((jsint)slot),
+ &pobj, &prop)) {
+ return JS_FALSE;
+ }
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ }
+ return JS_TRUE;
+}
+
+/*
+ * The Arguments class is not initialized via JS_InitClass, and must not be,
+ * because its name is "Object". Per ECMA, that causes instances of it to
+ * delegate to the object named by Object.prototype. It also ensures that
+ * arguments.toString() returns "[object Object]".
+ *
+ * The JSClass functions below collaborate to lazily reflect and synchronize
+ * actual argument values, argument count, and callee function object stored
+ * in a JSStackFrame with their corresponding property values in the frame's
+ * arguments object.
+ */
+JSClass js_ArgumentsClass = {
+ js_Object_str,
+ JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1),
+ JS_PropertyStub, args_delProperty,
+ args_getProperty, args_setProperty,
+ args_enumerate, (JSResolveOp) args_resolve,
+ JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+#endif /* JS_HAS_ARGS_OBJECT */
+
+#if JS_HAS_CALL_OBJECT
+
+JSObject *
+js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
+{
+ JSObject *callobj, *funobj;
+
+ /* Create a call object for fp only if it lacks one. */
+ JS_ASSERT(fp->fun);
+ callobj = fp->callobj;
+ if (callobj)
+ return callobj;
+ JS_ASSERT(fp->fun);
+
+ /* The default call parent is its function's parent (static link). */
+ if (!parent) {
+ funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
+ if (funobj)
+ parent = OBJ_GET_PARENT(cx, funobj);
+ }
+
+ /* Create the call object and link it to its stack frame. */
+ callobj = js_NewObject(cx, &js_CallClass, NULL, parent);
+ if (!callobj || !JS_SetPrivate(cx, callobj, fp)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ fp->callobj = callobj;
+
+ /* Make callobj be the scope chain and the variables object. */
+ fp->scopeChain = callobj;
+ fp->varobj = callobj;
+ return callobj;
+}
+
+static JSBool
+call_enumerate(JSContext *cx, JSObject *obj);
+
+JSBool
+js_PutCallObject(JSContext *cx, JSStackFrame *fp)
+{
+ JSObject *callobj;
+ JSBool ok;
+ jsid argsid;
+ jsval aval;
+
+ /*
+ * Reuse call_enumerate here to reflect all actual args and vars into the
+ * call object from fp.
+ */
+ callobj = fp->callobj;
+ if (!callobj)
+ return JS_TRUE;
+ ok = call_enumerate(cx, callobj);
+
+ /*
+ * Get the arguments object to snapshot fp's actual argument values.
+ */
+ if (fp->argsobj) {
+ argsid = (jsid) cx->runtime->atomState.argumentsAtom;
+ ok &= js_GetProperty(cx, callobj, argsid, &aval);
+ ok &= js_SetProperty(cx, callobj, argsid, &aval);
+ ok &= js_PutArgsObject(cx, fp);
+ }
+
+ /*
+ * Clear the private pointer to fp, which is about to go away (js_Invoke).
+ * Do this last because the call_enumerate and js_GetProperty calls above
+ * need to follow the private slot to find fp.
+ */
+ ok &= JS_SetPrivate(cx, callobj, NULL);
+ fp->callobj = NULL;
+ return ok;
+}
+
+static JSPropertySpec call_props[] = {
+ {js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT,0,0},
+ {"__callee__", CALL_CALLEE, 0,0,0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+call_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSStackFrame *fp;
+ jsint slot;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->fun);
+
+ slot = JSVAL_TO_INT(id);
+ switch (slot) {
+ case CALL_ARGUMENTS:
+ if (!TEST_OVERRIDE_BIT(fp, slot)) {
+ JSObject *argsobj = js_GetArgsObject(cx, fp);
+ if (!argsobj)
+ return JS_FALSE;
+ *vp = OBJECT_TO_JSVAL(argsobj);
+ }
+ break;
+
+ case CALL_CALLEE:
+ if (!TEST_OVERRIDE_BIT(fp, slot))
+ *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
+ break;
+
+ default:
+ if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
+ *vp = fp->argv[slot];
+ break;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+call_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSStackFrame *fp;
+ jsint slot;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->fun);
+
+ slot = JSVAL_TO_INT(id);
+ switch (slot) {
+ case CALL_ARGUMENTS:
+ case CALL_CALLEE:
+ SET_OVERRIDE_BIT(fp, slot);
+ break;
+
+ default:
+ if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
+ fp->argv[slot] = *vp;
+ break;
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_GetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSStackFrame *fp;
+
+ JS_ASSERT(JSVAL_IS_INT(id));
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
+ if (fp) {
+ /* XXX no jsint slot commoning here to avoid MSVC1.52 crashes */
+ if ((uintN)JSVAL_TO_INT(id) < fp->nvars)
+ *vp = fp->vars[JSVAL_TO_INT(id)];
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSStackFrame *fp;
+
+ JS_ASSERT(JSVAL_IS_INT(id));
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
+ if (fp) {
+ /* XXX jsint slot is block-local here to avoid MSVC1.52 crashes */
+ jsint slot = JSVAL_TO_INT(id);
+ if ((uintN)slot < fp->nvars)
+ fp->vars[slot] = *vp;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+call_enumerate(JSContext *cx, JSObject *obj)
+{
+ JSStackFrame *fp;
+ JSObject *funobj;
+ JSScope *scope;
+ JSScopeProperty *sprop, *cprop;
+ JSPropertyOp getter;
+ jsval *vec;
+ JSProperty *prop;
+
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
+ if (!fp)
+ return JS_TRUE;
+
+ /*
+ * Do not enumerate a cloned function object at fp->argv[-2], it may have
+ * gained its own (mutable) scope (e.g., a brutally-shared XUL script sets
+ * the clone's prototype property). We must enumerate the function object
+ * that was decorated with parameter and local variable properties by the
+ * compiler when the compiler created fp->fun, namely fp->fun->object.
+ *
+ * Contrast with call_resolve, where we prefer fp->argv[-2], because we'll
+ * use js_LookupProperty to find any overridden properties in that object,
+ * if it was a mutated clone; and if not, we will search its prototype,
+ * fp->fun->object, to find compiler-created params and locals.
+ */
+ funobj = fp->fun->object;
+ if (!funobj)
+ return JS_TRUE;
+
+ /*
+ * Reflect actual args from fp->argv for formal parameters, and local vars
+ * and functions in fp->vars for declared variables and nested-at-top-level
+ * local functions.
+ */
+ scope = OBJ_SCOPE(funobj);
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ getter = sprop->getter;
+ if (getter == js_GetArgument)
+ vec = fp->argv;
+ else if (getter == js_GetLocalVariable)
+ vec = fp->vars;
+ else
+ continue;
+
+ /* Trigger reflection in call_resolve by doing a lookup. */
+ if (!js_LookupProperty(cx, obj, sprop->id, &obj, &prop))
+ return JS_FALSE;
+ JS_ASSERT(obj && prop);
+ cprop = (JSScopeProperty *)prop;
+ LOCKED_OBJ_SET_SLOT(obj, cprop->slot, vec[sprop->shortid]);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
+ JSObject **objp)
+{
+ JSStackFrame *fp;
+ JSObject *funobj;
+ JSString *str;
+ JSAtom *atom;
+ JSObject *obj2;
+ JSScopeProperty *sprop;
+ jsid propid;
+ JSPropertyOp getter, setter;
+ uintN attrs, slot, nslots, spflags;
+ jsval *vp, value;
+ intN shortid;
+
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
+ if (!fp)
+ return JS_TRUE;
+ JS_ASSERT(fp->fun);
+
+ if (!JSVAL_IS_STRING(id))
+ return JS_TRUE;
+
+ funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
+ if (!funobj)
+ return JS_TRUE;
+
+ str = JSVAL_TO_STRING(id);
+ atom = js_AtomizeString(cx, str, 0);
+ if (!atom)
+ return JS_FALSE;
+ if (!js_LookupProperty(cx, funobj, (jsid)atom, &obj2,
+ (JSProperty **)&sprop)) {
+ return JS_FALSE;
+ }
+
+ if (sprop && OBJ_IS_NATIVE(obj2)) {
+ propid = sprop->id;
+ getter = sprop->getter;
+ attrs = sprop->attrs & ~JSPROP_SHARED;
+ slot = (uintN) sprop->shortid;
+ OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
+ if (getter == js_GetArgument || getter == js_GetLocalVariable) {
+ if (getter == js_GetArgument) {
+ vp = fp->argv;
+ nslots = JS_MAX(fp->argc, fp->fun->nargs);
+ getter = setter = NULL;
+ } else {
+ vp = fp->vars;
+ nslots = fp->nvars;
+ getter = js_GetCallVariable;
+ setter = js_SetCallVariable;
+ }
+ if (slot < nslots) {
+ value = vp[slot];
+ spflags = SPROP_HAS_SHORTID;
+ shortid = (intN) slot;
+ } else {
+ value = JSVAL_VOID;
+ spflags = 0;
+ shortid = 0;
+ }
+ if (!js_DefineNativeProperty(cx, obj, propid, value,
+ getter, setter, attrs,
+ spflags, shortid, NULL)) {
+ return JS_FALSE;
+ }
+ *objp = obj;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+{
+ JSStackFrame *fp;
+
+ if (type == JSTYPE_FUNCTION) {
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
+ if (fp) {
+ JS_ASSERT(fp->fun);
+ *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
+ }
+ }
+ return JS_TRUE;
+}
+
+JSClass js_CallClass = {
+ js_Call_str,
+ JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
+ JS_PropertyStub, JS_PropertyStub,
+ call_getProperty, call_setProperty,
+ call_enumerate, (JSResolveOp)call_resolve,
+ call_convert, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+#endif /* JS_HAS_CALL_OBJECT */
+
+/* SHARED because fun_getProperty always computes a new value. */
+#define FUNCTION_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
+
+static JSPropertySpec function_props[] = {
+ {js_arguments_str, CALL_ARGUMENTS, FUNCTION_PROP_ATTRS,0,0},
+ {js_arity_str, FUN_ARITY, FUNCTION_PROP_ATTRS,0,0},
+ {js_length_str, ARGS_LENGTH, FUNCTION_PROP_ATTRS,0,0},
+ {js_name_str, FUN_NAME, FUNCTION_PROP_ATTRS,0,0},
+ {js_caller_str, FUN_CALLER, FUNCTION_PROP_ATTRS,0,0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsint slot;
+ JSFunction *fun;
+ JSStackFrame *fp;
+#if defined _MSC_VER &&_MSC_VER <= 800
+ /* MSVC1.5 coredumps */
+ jsval bogus = *vp;
+#endif
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ slot = JSVAL_TO_INT(id);
+
+ /* No valid function object should lack private data, but check anyway. */
+ fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
+ if (!fun)
+ return JS_TRUE;
+
+ /* Find fun's top-most activation record. */
+ for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
+ fp = fp->down) {
+ continue;
+ }
+
+ switch (slot) {
+ case CALL_ARGUMENTS:
+#if JS_HAS_ARGS_OBJECT
+ /* Warn if strict about f.arguments or equivalent unqualified uses. */
+ if (!JS_ReportErrorFlagsAndNumber(cx,
+ JSREPORT_WARNING | JSREPORT_STRICT,
+ js_GetErrorMessage, NULL,
+ JSMSG_DEPRECATED_USAGE,
+ js_arguments_str)) {
+ return JS_FALSE;
+ }
+ if (fp) {
+ if (!js_GetArgsValue(cx, fp, vp))
+ return JS_FALSE;
+ } else {
+ *vp = JSVAL_NULL;
+ }
+ break;
+#else /* !JS_HAS_ARGS_OBJECT */
+ *vp = OBJECT_TO_JSVAL(fp ? obj : NULL);
+ break;
+#endif /* !JS_HAS_ARGS_OBJECT */
+
+ case ARGS_LENGTH:
+ if (!JSVERSION_IS_ECMA(cx->version))
+ *vp = INT_TO_JSVAL((jsint)(fp && fp->fun ? fp->argc : fun->nargs));
+ else
+ case FUN_ARITY:
+ *vp = INT_TO_JSVAL((jsint)fun->nargs);
+ break;
+
+ case FUN_NAME:
+ *vp = fun->atom
+ ? ATOM_KEY(fun->atom)
+ : STRING_TO_JSVAL(cx->runtime->emptyString);
+ break;
+
+ case FUN_CALLER:
+ while (fp && (fp->flags & JSFRAME_SKIP_CALLER) && fp->down)
+ fp = fp->down;
+ if (fp && fp->down && fp->down->fun && fp->down->argv)
+ *vp = fp->down->argv[-2];
+ else
+ *vp = JSVAL_NULL;
+ if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) {
+ id = ATOM_KEY(cx->runtime->atomState.callerAtom);
+ if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp))
+ return JS_FALSE;
+ }
+ break;
+
+ default:
+ /* XXX fun[0] and fun.arguments[0] are equivalent. */
+ if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
+#if defined _MSC_VER &&_MSC_VER <= 800
+ /* MSVC1.5 coredumps */
+ if (bogus == *vp)
+#endif
+ *vp = fp->argv[slot];
+ break;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
+ JSObject **objp)
+{
+ JSFunction *fun;
+ JSString *str;
+ JSAtom *prototypeAtom;
+
+ if (!JSVAL_IS_STRING(id))
+ return JS_TRUE;
+
+ /* No valid function object should lack private data, but check anyway. */
+ fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
+ if (!fun || !fun->object)
+ return JS_TRUE;
+
+ /* No need to reflect fun.prototype in 'fun.prototype = ...'. */
+ if (flags & JSRESOLVE_ASSIGNING)
+ return JS_TRUE;
+
+ /*
+ * Ok, check whether id is 'prototype' and bootstrap the function object's
+ * prototype property.
+ */
+ str = JSVAL_TO_STRING(id);
+ prototypeAtom = cx->runtime->atomState.classPrototypeAtom;
+ if (str == ATOM_TO_STRING(prototypeAtom)) {
+ JSObject *proto, *parentProto;
+ jsval pval;
+
+ proto = parentProto = NULL;
+ if (fun->object != obj && fun->object) {
+ /*
+ * Clone of a function: make its prototype property value have the
+ * same class as the clone-parent's prototype.
+ */
+ if (!OBJ_GET_PROPERTY(cx, fun->object, (jsid)prototypeAtom, &pval))
+ return JS_FALSE;
+ if (JSVAL_IS_OBJECT(pval))
+ parentProto = JSVAL_TO_OBJECT(pval);
+ }
+
+ /*
+ * Beware of the wacky case of a user function named Object -- trying
+ * to find a prototype for that will recur back here ad perniciem.
+ */
+ if (!parentProto && fun->atom == cx->runtime->atomState.ObjectAtom)
+ return JS_TRUE;
+
+ /*
+ * If resolving "prototype" in a clone, clone the parent's prototype.
+ * Pass the constructor's (obj's) parent as the prototype parent, to
+ * avoid defaulting to parentProto.constructor.__parent__.
+ */
+ proto = js_NewObject(cx, &js_ObjectClass, parentProto,
+ OBJ_GET_PARENT(cx, obj));
+ if (!proto)
+ return JS_FALSE;
+
+ /*
+ * ECMA says that constructor.prototype is DontEnum | DontDelete for
+ * user-defined functions, but DontEnum | ReadOnly | DontDelete for
+ * native "system" constructors such as Object or Function. So lazily
+ * set the former here in fun_resolve, but eagerly define the latter
+ * in JS_InitClass, with the right attributes.
+ */
+ if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return JS_FALSE;
+ }
+ *objp = obj;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+{
+ switch (type) {
+ case JSTYPE_FUNCTION:
+ *vp = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+ default:
+ return js_TryValueOf(cx, obj, type, vp);
+ }
+}
+
+static void
+fun_finalize(JSContext *cx, JSObject *obj)
+{
+ JSFunction *fun;
+
+ /* No valid function object should lack private data, but check anyway. */
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ if (!fun)
+ return;
+ if (fun->object == obj)
+ fun->object = NULL;
+ JS_ATOMIC_DECREMENT(&fun->nrefs);
+ if (fun->nrefs)
+ return;
+ if (fun->script)
+ js_DestroyScript(cx, fun->script);
+ JS_free(cx, fun);
+}
+
+#if JS_HAS_XDR
+
+#include "jsxdrapi.h"
+
+enum {
+ JSXDR_FUNARG = 1,
+ JSXDR_FUNVAR = 2,
+ JSXDR_FUNCONST = 3
+};
+
+/* XXX store parent and proto, if defined */
+static JSBool
+fun_xdrObject(JSXDRState *xdr, JSObject **objp)
+{
+ JSContext *cx;
+ JSFunction *fun;
+ JSString *atomstr;
+ char *propname;
+ JSScopeProperty *sprop;
+ uint32 userid; /* NB: holds a signed int-tagged jsval */
+ JSAtom *atom;
+ uintN i, n, dupflag;
+ uint32 type;
+#ifdef DEBUG
+ uintN nvars = 0, nargs = 0;
+#endif
+
+ cx = xdr->cx;
+ if (xdr->mode == JSXDR_ENCODE) {
+ /*
+ * No valid function object should lack private data, but fail soft
+ * (return true, no error report) in case one does due to API pilot
+ * or internal error.
+ */
+ fun = (JSFunction *) JS_GetPrivate(cx, *objp);
+ if (!fun)
+ return JS_TRUE;
+ atomstr = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
+ } else {
+ fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL);
+ if (!fun)
+ return JS_FALSE;
+ atomstr = NULL;
+ }
+
+ if (!JS_XDRStringOrNull(xdr, &atomstr) ||
+ !JS_XDRUint16(xdr, &fun->nargs) ||
+ !JS_XDRUint16(xdr, &fun->extra) ||
+ !JS_XDRUint16(xdr, &fun->nvars) ||
+ !JS_XDRUint8(xdr, &fun->flags)) {
+ return JS_FALSE;
+ }
+
+ /* do arguments and local vars */
+ if (fun->object) {
+ n = fun->nargs + fun->nvars;
+ if (xdr->mode == JSXDR_ENCODE) {
+ JSScope *scope;
+ JSScopeProperty **spvec, *auto_spvec[8];
+ void *mark;
+
+ if (n <= sizeof auto_spvec / sizeof auto_spvec[0]) {
+ spvec = auto_spvec;
+ mark = NULL;
+ } else {
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ JS_ARENA_ALLOCATE_CAST(spvec, JSScopeProperty **, &cx->tempPool,
+ n * sizeof(JSScopeProperty *));
+ if (!spvec) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ }
+ scope = OBJ_SCOPE(fun->object);
+ for (sprop = SCOPE_LAST_PROP(scope); sprop;
+ sprop = sprop->parent) {
+ if (sprop->getter == js_GetArgument) {
+ JS_ASSERT(nargs++ <= fun->nargs);
+ spvec[sprop->shortid] = sprop;
+ } else if (sprop->getter == js_GetLocalVariable) {
+ JS_ASSERT(nvars++ <= fun->nvars);
+ spvec[fun->nargs + sprop->shortid] = sprop;
+ }
+ }
+ for (i = 0; i < n; i++) {
+ sprop = spvec[i];
+ JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
+ type = (i < fun->nargs)
+ ? JSXDR_FUNARG
+ : (sprop->attrs & JSPROP_READONLY)
+ ? JSXDR_FUNCONST
+ : JSXDR_FUNVAR;
+ userid = INT_TO_JSVAL(sprop->shortid);
+ /* XXX lossy conversion, need new XDR version for ECMAv3 */
+ propname = JS_GetStringBytes(ATOM_TO_STRING((JSAtom *)sprop->id));
+ if (!propname ||
+ !JS_XDRUint32(xdr, &type) ||
+ !JS_XDRUint32(xdr, &userid) ||
+ !JS_XDRCString(xdr, &propname)) {
+ if (mark)
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return JS_FALSE;
+ }
+ }
+ if (mark)
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ } else {
+ JSPropertyOp getter, setter;
+
+ for (i = n; i != 0; i--) {
+ uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
+
+ if (!JS_XDRUint32(xdr, &type) ||
+ !JS_XDRUint32(xdr, &userid) ||
+ !JS_XDRCString(xdr, &propname)) {
+ return JS_FALSE;
+ }
+ JS_ASSERT(type == JSXDR_FUNARG || type == JSXDR_FUNVAR ||
+ type == JSXDR_FUNCONST);
+ if (type == JSXDR_FUNARG) {
+ getter = js_GetArgument;
+ setter = js_SetArgument;
+ JS_ASSERT(nargs++ <= fun->nargs);
+ } else if (type == JSXDR_FUNVAR || type == JSXDR_FUNCONST) {
+ getter = js_GetLocalVariable;
+ setter = js_SetLocalVariable;
+ if (type == JSXDR_FUNCONST)
+ attrs |= JSPROP_READONLY;
+ JS_ASSERT(nvars++ <= fun->nvars);
+ } else {
+ getter = NULL;
+ setter = NULL;
+ }
+ atom = js_Atomize(cx, propname, strlen(propname), 0);
+ JS_free(cx, propname);
+ if (!atom)
+ return JS_FALSE;
+
+ /* Flag duplicate argument if atom is bound in fun->object. */
+ dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object), (jsid)atom)
+ ? SPROP_IS_DUPLICATE
+ : 0;
+
+ if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
+ getter, setter, SPROP_INVALID_SLOT,
+ attrs | JSPROP_SHARED,
+ SPROP_HAS_SHORTID | dupflag,
+ JSVAL_TO_INT(userid))) {
+ return JS_FALSE;
+ }
+ }
+ }
+ }
+
+ if (!js_XDRScript(xdr, &fun->script, NULL))
+ return JS_FALSE;
+
+ if (xdr->mode == JSXDR_DECODE) {
+ *objp = fun->object;
+ if (atomstr) {
+ fun->atom = js_AtomizeString(cx, atomstr, 0);
+ if (!fun->atom)
+ return JS_FALSE;
+
+ if (!OBJ_DEFINE_PROPERTY(cx, cx->globalObject,
+ (jsid)fun->atom, OBJECT_TO_JSVAL(*objp),
+ NULL, NULL, JSPROP_ENUMERATE,
+ NULL)) {
+ return JS_FALSE;
+ }
+ }
+
+ js_CallNewScriptHook(cx, fun->script, fun);
+ }
+
+ return JS_TRUE;
+}
+
+#else /* !JS_HAS_XDR */
+
+#define fun_xdrObject NULL
+
+#endif /* !JS_HAS_XDR */
+
+#if JS_HAS_INSTANCEOF
+
+/*
+ * [[HasInstance]] internal method for Function objects: fetch the .prototype
+ * property of its 'this' parameter, and walks the prototype chain of v (only
+ * if v is an object) returning true if .prototype is found.
+ */
+static JSBool
+fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+{
+ jsval pval, cval;
+ JSString *str;
+ JSObject *proto, *obj2;
+ JSFunction *cfun, *ofun;
+
+ if (!OBJ_GET_PROPERTY(cx, obj,
+ (jsid)cx->runtime->atomState.classPrototypeAtom,
+ &pval)) {
+ return JS_FALSE;
+ }
+
+ if (JSVAL_IS_PRIMITIVE(pval)) {
+ /*
+ * Throw a runtime error if instanceof is called on a function that
+ * has a non-object as its .prototype value.
+ */
+ str = js_DecompileValueGenerator(cx, -1, OBJECT_TO_JSVAL(obj), NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_PROTOTYPE, JS_GetStringBytes(str));
+ }
+ return JS_FALSE;
+ }
+
+ proto = JSVAL_TO_OBJECT(pval);
+ if (!js_IsDelegate(cx, proto, v, bp))
+ return JS_FALSE;
+
+ if (!*bp && !JSVAL_IS_PRIMITIVE(v)) {
+ /*
+ * Extension for "brutal sharing" of standard class constructors: if
+ * a script is compiled using a single, shared set of constructors, in
+ * particular Function and RegExp, but executed many times using other
+ * sets of standard constructors, then (/re/ instanceof RegExp), e.g.,
+ * will be false.
+ *
+ * We extend instanceof in this case to look for a matching native or
+ * script underlying the function object found in the 'constructor'
+ * property of the object in question (which is JSVAL_TO_OBJECT(v)),
+ * or found in the 'constructor' property of one of its prototypes.
+ *
+ * See also jsexn.c, where the *Error constructors are defined, each
+ * with its own native function, to satisfy (e instanceof Error) even
+ * when exceptions cross standard-class sharing boundaries. Note that
+ * Error.prototype may not lie on e's __proto__ chain in that case.
+ */
+ obj2 = JSVAL_TO_OBJECT(v);
+ do {
+ if (!OBJ_GET_PROPERTY(cx, obj2,
+ (jsid)cx->runtime->atomState.constructorAtom,
+ &cval)) {
+ return JS_FALSE;
+ }
+
+ if (JSVAL_IS_FUNCTION(cx, cval)) {
+ cfun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(cval));
+ ofun = (JSFunction *) JS_GetPrivate(cx, obj);
+ if (cfun->native == ofun->native &&
+ cfun->script == ofun->script) {
+ *bp = JS_TRUE;
+ break;
+ }
+ }
+ } while ((obj2 = OBJ_GET_PROTO(cx, obj2)) != NULL);
+ }
+
+ return JS_TRUE;
+}
+
+#else /* !JS_HAS_INSTANCEOF */
+
+#define fun_hasInstance NULL
+
+#endif /* !JS_HAS_INSTANCEOF */
+
+static uint32
+fun_mark(JSContext *cx, JSObject *obj, void *arg)
+{
+ JSFunction *fun;
+
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ if (fun) {
+ if (fun->atom)
+ GC_MARK_ATOM(cx, fun->atom, arg);
+ if (fun->script)
+ js_MarkScript(cx, fun->script, arg);
+ }
+ return 0;
+}
+
+/*
+ * Reserve two slots in all function objects for XPConnect. Note that this
+ * does not bloat every instance, only those on which reserved slots are set,
+ * and those on which ad-hoc properties are defined.
+ */
+JSClass js_FunctionClass = {
+ js_Function_str,
+ JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2),
+ JS_PropertyStub, JS_PropertyStub,
+ fun_getProperty, JS_PropertyStub,
+ JS_EnumerateStub, (JSResolveOp)fun_resolve,
+ fun_convert, fun_finalize,
+ NULL, NULL,
+ NULL, NULL,
+ fun_xdrObject, fun_hasInstance,
+ fun_mark, 0
+};
+
+JSBool
+js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent,
+ uintN argc, jsval *argv, jsval *rval)
+{
+ jsval fval;
+ JSFunction *fun;
+ JSString *str;
+
+ if (!argv) {
+ JS_ASSERT(JS_ObjectIsFunction(cx, obj));
+ } else {
+ fval = argv[-1];
+ if (!JSVAL_IS_FUNCTION(cx, fval)) {
+ /*
+ * If we don't have a function to start off with, try converting
+ * the object to a function. If that doesn't work, complain.
+ */
+ if (JSVAL_IS_OBJECT(fval)) {
+ obj = JSVAL_TO_OBJECT(fval);
+ if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION,
+ &fval)) {
+ return JS_FALSE;
+ }
+ }
+ if (!JSVAL_IS_FUNCTION(cx, fval)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_INCOMPATIBLE_PROTO,
+ js_Function_str, js_toString_str,
+ JS_GetTypeName(cx,
+ JS_TypeOfValue(cx, fval)));
+ return JS_FALSE;
+ }
+ }
+
+ obj = JSVAL_TO_OBJECT(fval);
+ }
+
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ if (!fun)
+ return JS_TRUE;
+ if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
+ return JS_FALSE;
+ str = JS_DecompileFunction(cx, fun, (uintN)indent);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return js_fun_toString(cx, obj, 0, argc, argv, rval);
+}
+
+#if JS_HAS_TOSOURCE
+static JSBool
+fun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return js_fun_toString(cx, obj, JS_DONT_PRETTY_PRINT, argc, argv, rval);
+}
+#endif
+
+static const char js_call_str[] = "call";
+
+#if JS_HAS_CALL_FUNCTION
+static JSBool
+fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval fval, *sp, *oldsp;
+ void *mark;
+ uintN i;
+ JSStackFrame *fp;
+ JSBool ok;
+
+ if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
+ return JS_FALSE;
+ fval = argv[-1];
+
+ if (!JSVAL_IS_FUNCTION(cx, fval)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_INCOMPATIBLE_PROTO,
+ js_Function_str, js_call_str,
+ JS_GetStringBytes(JS_ValueToString(cx, fval)));
+ return JS_FALSE;
+ }
+
+ if (argc == 0) {
+ /* Call fun with its parent as the 'this' parameter if no args. */
+ obj = OBJ_GET_PARENT(cx, obj);
+ } else {
+ /* Otherwise convert the first arg to 'this' and skip over it. */
+ if (!js_ValueToObject(cx, argv[0], &obj))
+ return JS_FALSE;
+ argc--;
+ argv++;
+ }
+
+ /* Allocate stack space for fval, obj, and the args. */
+ sp = js_AllocStack(cx, 2 + argc, &mark);
+ if (!sp)
+ return JS_FALSE;
+
+ /* Push fval, obj, and the args. */
+ *sp++ = fval;
+ *sp++ = OBJECT_TO_JSVAL(obj);
+ for (i = 0; i < argc; i++)
+ *sp++ = argv[i];
+
+ /* Lift current frame to include the args and do the call. */
+ fp = cx->fp;
+ oldsp = fp->sp;
+ fp->sp = sp;
+ ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
+
+ /* Store rval and pop stack back to our frame's sp. */
+ *rval = fp->sp[-1];
+ fp->sp = oldsp;
+ js_FreeStack(cx, mark);
+ return ok;
+}
+#endif /* JS_HAS_CALL_FUNCTION */
+
+#if JS_HAS_APPLY_FUNCTION
+static JSBool
+fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval fval, *sp, *oldsp;
+ JSObject *aobj;
+ jsuint length;
+ void *mark;
+ uintN i;
+ JSBool ok;
+ JSStackFrame *fp;
+
+ if (argc == 0) {
+ /* Will get globalObject as 'this' and no other agurments. */
+ return fun_call(cx, obj, argc, argv, rval);
+ }
+
+ if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
+ return JS_FALSE;
+ fval = argv[-1];
+
+ if (!JSVAL_IS_FUNCTION(cx, fval)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_INCOMPATIBLE_PROTO,
+ js_Function_str, "apply",
+ JS_GetStringBytes(JS_ValueToString(cx, fval)));
+ return JS_FALSE;
+ }
+
+ /* Quell GCC overwarnings. */
+ aobj = NULL;
+ length = 0;
+
+ if (argc >= 2) {
+ /* If the 2nd arg is null or void, call the function with 0 args. */
+ if (JSVAL_IS_NULL(argv[1]) || JSVAL_IS_VOID(argv[1])) {
+ argc = 0;
+ } else {
+ /* The second arg must be an array (or arguments object). */
+ if (JSVAL_IS_PRIMITIVE(argv[1]) ||
+ (aobj = JSVAL_TO_OBJECT(argv[1]),
+ OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass &&
+ OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass))
+ {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_APPLY_ARGS);
+ return JS_FALSE;
+ }
+ if (!js_GetLengthProperty(cx, aobj, &length))
+ return JS_FALSE;
+ }
+ }
+
+ /* Convert the first arg to 'this' and skip over it. */
+ if (!js_ValueToObject(cx, argv[0], &obj))
+ return JS_FALSE;
+
+ /* Allocate stack space for fval, obj, and the args. */
+ argc = (uintN)JS_MIN(length, ARGC_LIMIT - 1);
+ sp = js_AllocStack(cx, 2 + argc, &mark);
+ if (!sp)
+ return JS_FALSE;
+
+ /* Push fval, obj, and aobj's elements as args. */
+ *sp++ = fval;
+ *sp++ = OBJECT_TO_JSVAL(obj);
+ for (i = 0; i < argc; i++) {
+ ok = JS_GetElement(cx, aobj, (jsint)i, sp);
+ if (!ok)
+ goto out;
+ sp++;
+ }
+
+ /* Lift current frame to include the args and do the call. */
+ fp = cx->fp;
+ oldsp = fp->sp;
+ fp->sp = sp;
+ ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
+
+ /* Store rval and pop stack back to our frame's sp. */
+ *rval = fp->sp[-1];
+ fp->sp = oldsp;
+out:
+ js_FreeStack(cx, mark);
+ return ok;
+}
+#endif /* JS_HAS_APPLY_FUNCTION */
+
+static JSFunctionSpec function_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, fun_toSource, 0,0,0},
+#endif
+ {js_toString_str, fun_toString, 1,0,0},
+#if JS_HAS_APPLY_FUNCTION
+ {"apply", fun_apply, 2,0,0},
+#endif
+#if JS_HAS_CALL_FUNCTION
+ {js_call_str, fun_call, 1,0,0},
+#endif
+ {0,0,0,0,0}
+};
+
+JSBool
+js_IsIdentifier(JSString *str)
+{
+ size_t n;
+ jschar *s, c;
+
+ n = JSSTRING_LENGTH(str);
+ if (n == 0)
+ return JS_FALSE;
+ s = JSSTRING_CHARS(str);
+ c = *s;
+ if (!JS_ISIDENT_START(c))
+ return JS_FALSE;
+ for (n--; n != 0; n--) {
+ c = *++s;
+ if (!JS_ISIDENT(c))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSStackFrame *fp, *caller;
+ JSFunction *fun;
+ JSObject *parent;
+ uintN i, n, lineno, dupflag;
+ JSAtom *atom;
+ const char *filename;
+ JSObject *obj2;
+ JSScopeProperty *sprop;
+ JSString *str, *arg;
+ void *mark;
+ JSTokenStream *ts;
+ JSPrincipals *principals;
+ jschar *collected_args, *cp;
+ size_t arg_length, args_length;
+ JSTokenType tt;
+ JSBool ok;
+
+ fp = cx->fp;
+ if (fp && !(fp->flags & JSFRAME_CONSTRUCTING)) {
+ obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ }
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ if (fun)
+ return JS_TRUE;
+
+#if JS_HAS_CALL_OBJECT
+ /*
+ * NB: (new Function) is not lexically closed by its caller, it's just an
+ * anonymous function in the top-level scope that its constructor inhabits.
+ * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
+ * and so would a call to f from another top-level's script or function.
+ *
+ * In older versions, before call objects, a new Function was adopted by
+ * its running context's globalObject, which might be different from the
+ * top-level reachable from scopeChain (in HTML frames, e.g.).
+ */
+ parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
+#else
+ /* Set up for dynamic parenting (see js_Invoke in jsinterp.c). */
+ parent = NULL;
+#endif
+
+ fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA, parent,
+ JSVERSION_IS_ECMA(cx->version)
+ ? cx->runtime->atomState.anonymousAtom
+ : NULL);
+
+ if (!fun)
+ return JS_FALSE;
+
+ /*
+ * Function is static and not called directly by other functions in this
+ * file, therefore it is callable only as a native function by js_Invoke.
+ * Find the scripted caller, possibly skipping other native frames such as
+ * are built for Function.prototype.call or .apply activations that invoke
+ * Function indirectly from a script.
+ */
+ JS_ASSERT(!fp->script && fp->fun && fp->fun->native == Function);
+ caller = JS_GetScriptedCaller(cx, fp);
+ if (caller) {
+ filename = caller->script->filename;
+ lineno = js_PCToLineNumber(cx, caller->script, caller->pc);
+ principals = JS_EvalFramePrincipals(cx, fp, caller);
+ } else {
+ filename = NULL;
+ lineno = 0;
+ principals = NULL;
+ }
+
+ n = argc ? argc - 1 : 0;
+ if (n > 0) {
+ /*
+ * Collect the function-argument arguments into one string, separated
+ * by commas, then make a tokenstream from that string, and scan it to
+ * get the arguments. We need to throw the full scanner at the
+ * problem, because the argument string can legitimately contain
+ * comments and linefeeds. XXX It might be better to concatenate
+ * everything up into a function definition and pass it to the
+ * compiler, but doing it this way is less of a delta from the old
+ * code. See ECMA 15.3.2.1.
+ */
+ args_length = 0;
+ for (i = 0; i < n; i++) {
+ /* Collect the lengths for all the function-argument arguments. */
+ arg = js_ValueToString(cx, argv[i]);
+ if (!arg)
+ return JS_FALSE;
+ argv[i] = STRING_TO_JSVAL(arg);
+ args_length += JSSTRING_LENGTH(arg);
+ }
+ /* Add 1 for each joining comma. */
+ args_length += n - 1;
+
+ /*
+ * Allocate a string to hold the concatenated arguments, including room
+ * for a terminating 0. Mark cx->tempPool for later release, to free
+ * collected_args and its tokenstream in one swoop.
+ */
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
+ (args_length+1) * sizeof(jschar));
+ if (!cp)
+ return JS_FALSE;
+ collected_args = cp;
+
+ /*
+ * Concatenate the arguments into the new string, separated by commas.
+ */
+ for (i = 0; i < n; i++) {
+ arg = JSVAL_TO_STRING(argv[i]);
+ arg_length = JSSTRING_LENGTH(arg);
+ (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length);
+ cp += arg_length;
+
+ /* Add separating comma or terminating 0. */
+ *cp++ = (i + 1 < n) ? ',' : 0;
+ }
+
+ /*
+ * Make a tokenstream (allocated from cx->tempPool) that reads from
+ * the given string.
+ */
+ ts = js_NewTokenStream(cx, collected_args, args_length, filename,
+ lineno, principals);
+ if (!ts) {
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return JS_FALSE;
+ }
+
+ /* The argument string may be empty or contain no tokens. */
+ tt = js_GetToken(cx, ts);
+ if (tt != TOK_EOF) {
+ for (;;) {
+ /*
+ * Check that it's a name. This also implicitly guards against
+ * TOK_ERROR, which was already reported.
+ */
+ if (tt != TOK_NAME)
+ goto bad_formal;
+
+ /*
+ * Get the atom corresponding to the name from the tokenstream;
+ * we're assured at this point that it's a valid identifier.
+ */
+ atom = CURRENT_TOKEN(ts).t_atom;
+ if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
+ (JSProperty **)&sprop)) {
+ goto bad_formal;
+ }
+ dupflag = 0;
+ if (sprop) {
+ ok = JS_TRUE;
+ if (obj2 == obj) {
+ const char *name = js_AtomToPrintableString(cx, atom);
+
+ /*
+ * A duplicate parameter name. We force a duplicate
+ * node on the SCOPE_LAST_PROP(scope) list with the
+ * same id, distinguished by the SPROP_IS_DUPLICATE
+ * flag, and not mapped by an entry in scope.
+ */
+ JS_ASSERT(sprop->getter == js_GetArgument);
+ ok = name &&
+ js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_DUPLICATE_FORMAL,
+ name);
+
+ dupflag = SPROP_IS_DUPLICATE;
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
+ if (!ok)
+ goto bad_formal;
+ sprop = NULL;
+ }
+ if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
+ js_GetArgument, js_SetArgument,
+ SPROP_INVALID_SLOT,
+ JSPROP_ENUMERATE | JSPROP_PERMANENT |
+ JSPROP_SHARED,
+ SPROP_HAS_SHORTID | dupflag,
+ fun->nargs)) {
+ goto bad_formal;
+ }
+ fun->nargs++;
+
+ /*
+ * Get the next token. Stop on end of stream. Otherwise
+ * insist on a comma, get another name, and iterate.
+ */
+ tt = js_GetToken(cx, ts);
+ if (tt == TOK_EOF)
+ break;
+ if (tt != TOK_COMMA)
+ goto bad_formal;
+ tt = js_GetToken(cx, ts);
+ }
+ }
+
+ /* Clean up. */
+ ok = js_CloseTokenStream(cx, ts);
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ if (!ok)
+ return JS_FALSE;
+ }
+
+ if (argc) {
+ str = js_ValueToString(cx, argv[argc-1]);
+ } else {
+ /* Can't use cx->runtime->emptyString because we're called too early. */
+ str = js_NewStringCopyZ(cx, js_empty_ucstr, 0);
+ }
+ if (!str)
+ return JS_FALSE;
+ if (argv) {
+ /* Use the last arg (or this if argc == 0) as a local GC root. */
+ argv[(intN)(argc-1)] = STRING_TO_JSVAL(str);
+ }
+
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewTokenStream(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
+ filename, lineno, principals);
+ if (!ts) {
+ ok = JS_FALSE;
+ } else {
+ ok = js_CompileFunctionBody(cx, ts, fun) &&
+ js_CloseTokenStream(cx, ts);
+ }
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return ok;
+
+bad_formal:
+ /*
+ * Report "malformed formal parameter" iff no illegal char or similar
+ * scanner error was already reported.
+ */
+ if (!(ts->flags & TSF_ERROR))
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL);
+
+ /*
+ * Clean up the arguments string and tokenstream if we failed to parse
+ * the arguments.
+ */
+ (void)js_CloseTokenStream(cx, ts);
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return JS_FALSE;
+}
+
+JSObject *
+js_InitFunctionClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+ JSAtom *atom;
+ JSFunction *fun;
+
+ proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
+ function_props, function_methods, NULL, NULL);
+ if (!proto)
+ return NULL;
+ atom = js_Atomize(cx, js_FunctionClass.name, strlen(js_FunctionClass.name),
+ 0);
+ if (!atom)
+ goto bad;
+ fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
+ if (!fun)
+ goto bad;
+ fun->script = js_NewScript(cx, 0, 0, 0);
+ if (!fun->script)
+ goto bad;
+ return proto;
+
+bad:
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+}
+
+#if JS_HAS_CALL_OBJECT
+JSObject *
+js_InitCallClass(JSContext *cx, JSObject *obj)
+{
+ return JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,
+ call_props, NULL, NULL, NULL);
+}
+#endif
+
+JSFunction *
+js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
+ uintN flags, JSObject *parent, JSAtom *atom)
+{
+ JSFunction *fun;
+
+ /* Allocate a function struct. */
+ fun = (JSFunction *) JS_malloc(cx, sizeof *fun);
+ if (!fun)
+ return NULL;
+
+ /* If funobj is null, allocate an object for it. */
+ if (funobj) {
+ OBJ_SET_PARENT(cx, funobj, parent);
+ } else {
+ funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
+ if (!funobj) {
+ JS_free(cx, fun);
+ return NULL;
+ }
+ }
+
+ /* Initialize all function members. */
+ fun->nrefs = 0;
+ fun->object = NULL;
+ fun->native = native;
+ fun->script = NULL;
+ fun->nargs = nargs;
+ fun->extra = 0;
+ fun->nvars = 0;
+ fun->flags = flags & JSFUN_FLAGS_MASK;
+ fun->spare = 0;
+ fun->atom = atom;
+ fun->clasp = NULL;
+
+ /* Link fun to funobj and vice versa. */
+ if (!js_LinkFunctionObject(cx, fun, funobj)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ JS_free(cx, fun);
+ return NULL;
+ }
+ return fun;
+}
+
+JSObject *
+js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
+{
+ JSObject *newfunobj;
+ JSFunction *fun;
+
+ JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
+ newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent);
+ if (!newfunobj)
+ return NULL;
+ fun = (JSFunction *) JS_GetPrivate(cx, funobj);
+ if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ return newfunobj;
+}
+
+JSBool
+js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *funobj)
+{
+ if (!fun->object)
+ fun->object = funobj;
+ if (!JS_SetPrivate(cx, funobj, fun))
+ return JS_FALSE;
+ JS_ATOMIC_INCREMENT(&fun->nrefs);
+ return JS_TRUE;
+}
+
+JSFunction *
+js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
+ uintN nargs, uintN attrs)
+{
+ JSFunction *fun;
+
+ fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
+ if (!fun)
+ return NULL;
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, OBJECT_TO_JSVAL(fun->object),
+ NULL, NULL, attrs & ~JSFUN_FLAGS_MASK, NULL)) {
+ return NULL;
+ }
+ return fun;
+}
+
+#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
+# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
+#endif
+
+JSFunction *
+js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
+{
+ jsval v;
+ JSObject *obj;
+
+ v = *vp;
+ obj = NULL;
+ if (JSVAL_IS_OBJECT(v)) {
+ obj = JSVAL_TO_OBJECT(v);
+ if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
+ if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v))
+ return NULL;
+ obj = JSVAL_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL;
+ }
+ }
+ if (!obj) {
+ js_ReportIsNotFunction(cx, vp, flags);
+ return NULL;
+ }
+ return (JSFunction *) JS_GetPrivate(cx, obj);
+}
+
+void
+js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
+{
+ JSType type;
+ JSString *fallback;
+ JSString *str;
+
+ /*
+ * We provide the typename as the fallback to handle the case when
+ * valueOf is not a function, which prevents ValueToString from being
+ * called as the default case inside js_DecompileValueGenerator (and
+ * so recursing back to here).
+ */
+ type = JS_TypeOfValue(cx, *vp);
+ fallback = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
+ str = js_DecompileValueGenerator(cx,
+ (flags & JSV2F_SEARCH_STACK)
+ ? JSDVG_SEARCH_STACK
+ : cx->fp
+ ? vp - cx->fp->sp
+ : JSDVG_IGNORE_STACK,
+ *vp,
+ fallback);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ (uintN)((flags & JSV2F_CONSTRUCT)
+ ? JSMSG_NOT_CONSTRUCTOR
+ : JSMSG_NOT_FUNCTION),
+ JS_GetStringBytes(str));
+ }
+}
diff --git a/src/dom/js/jsfun.h b/src/dom/js/jsfun.h
new file mode 100644
index 000000000..0a3237921
--- /dev/null
+++ b/src/dom/js/jsfun.h
@@ -0,0 +1,151 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsfun_h___
+#define jsfun_h___
+/*
+ * JS function definitions.
+ */
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+struct JSFunction {
+ jsrefcount nrefs; /* number of referencing objects */
+ JSObject *object; /* back-pointer to GC'ed object header */
+ JSNative native; /* native method pointer or null */
+ JSScript *script; /* interpreted bytecode descriptor or null */
+ uint16 nargs; /* minimum number of actual arguments */
+ uint16 extra; /* number of arg slots for local GC roots */
+ uint16 nvars; /* number of local variables */
+ uint8 flags; /* bound method and other flags, see jsapi.h */
+ uint8 spare; /* reserved for future use */
+ JSAtom *atom; /* name for diagnostics and decompiling */
+ JSClass *clasp; /* if non-null, constructor for this class */
+};
+
+extern JSClass js_ArgumentsClass;
+extern JSClass js_CallClass;
+
+/* JS_FRIEND_DATA so that JSVAL_IS_FUNCTION is callable from outside */
+extern JS_FRIEND_DATA(JSClass) js_FunctionClass;
+
+/*
+ * NB: jsapi.h and jsobj.h must be included before any call to this macro.
+ */
+#define JSVAL_IS_FUNCTION(cx, v) \
+ (JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) && \
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass)
+
+extern JSBool
+js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent,
+ uintN argc, jsval *argv, jsval *rval);
+
+extern JSBool
+js_IsIdentifier(JSString *str);
+
+extern JSObject *
+js_InitFunctionClass(JSContext *cx, JSObject *obj);
+
+extern JSObject *
+js_InitArgumentsClass(JSContext *cx, JSObject *obj);
+
+extern JSObject *
+js_InitCallClass(JSContext *cx, JSObject *obj);
+
+extern JSFunction *
+js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
+ uintN flags, JSObject *parent, JSAtom *atom);
+
+extern JSObject *
+js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
+
+extern JSBool
+js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *object);
+
+extern JSFunction *
+js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
+ uintN nargs, uintN flags);
+
+/*
+ * Flags for js_ValueToFunction and js_ReportIsNotFunction. We depend on the
+ * fact that JSINVOKE_CONSTRUCT (aka JSFRAME_CONSTRUCTING) is 1, and test that
+ * with #if/#error in jsfun.c.
+ */
+#define JSV2F_CONSTRUCT JSINVOKE_CONSTRUCT
+#define JSV2F_SEARCH_STACK 2
+
+extern JSFunction *
+js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags);
+
+extern void
+js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags);
+
+extern JSObject *
+js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent);
+
+extern JSBool
+js_PutCallObject(JSContext *cx, JSStackFrame *fp);
+
+extern JSBool
+js_GetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+extern JSBool
+js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+extern JSBool
+js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp);
+
+extern JSBool
+js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id,
+ JSObject **objp, jsval *vp);
+
+extern JSObject *
+js_GetArgsObject(JSContext *cx, JSStackFrame *fp);
+
+extern JSBool
+js_PutArgsObject(JSContext *cx, JSStackFrame *fp);
+
+extern JSBool
+js_XDRFunction(JSXDRState *xdr, JSObject **objp);
+
+JS_END_EXTERN_C
+
+#endif /* jsfun_h___ */
diff --git a/src/dom/js/jsgc.c b/src/dom/js/jsgc.c
new file mode 100644
index 000000000..a0efec4d7
--- /dev/null
+++ b/src/dom/js/jsgc.c
@@ -0,0 +1,1423 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS Mark-and-Sweep Garbage Collector.
+ *
+ * This GC allocates only fixed-sized things big enough to contain two words
+ * (pointers) on any host architecture. It allocates from an arena pool (see
+ * jsarena.h). It uses an ideally parallel array of flag bytes to hold the
+ * mark bit, finalizer type index, etc.
+ *
+ * XXX swizzle page to freelist for better locality of reference
+ */
+#include "jsstddef.h"
+#include <stdlib.h> /* for free, called by JS_ARENA_DESTROY */
+#include <string.h> /* for memset, called by jsarena.h macros if DEBUG */
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jshash.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdbgapi.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+/*
+ * GC arena sizing depends on amortizing arena overhead using a large number
+ * of things per arena, and on the thing/flags ratio of 8:1 on most platforms.
+ *
+ * On 64-bit platforms, we would have half as many things per arena because
+ * pointers are twice as big, so we double the bytes for things per arena.
+ * This preserves the 1024 byte flags sub-arena size, which relates to the
+ * GC_PAGE_SIZE (see below for why).
+ */
+#if JS_BYTES_PER_WORD == 8
+# define GC_THINGS_SHIFT 14 /* 16KB for things on Alpha, etc. */
+#else
+# define GC_THINGS_SHIFT 13 /* 8KB for things on most platforms */
+#endif
+#define GC_THINGS_SIZE JS_BIT(GC_THINGS_SHIFT)
+#define GC_FLAGS_SIZE (GC_THINGS_SIZE / sizeof(JSGCThing))
+#define GC_ARENA_SIZE (GC_THINGS_SIZE + GC_FLAGS_SIZE)
+
+/*
+ * The private JSGCThing struct, which describes a gcFreeList element.
+ */
+struct JSGCThing {
+ JSGCThing *next;
+ uint8 *flagp;
+};
+
+/*
+ * A GC arena contains one flag byte for each thing in its heap, and supports
+ * O(1) lookup of a flag given its thing's address.
+ *
+ * To implement this, we take advantage of the thing/flags numerology: given
+ * the 8K bytes worth of GC-things, there are 1K flag bytes. We mask a thing's
+ * address with ~1023 to find a JSGCPageInfo record at the front of a mythical
+ * "GC page" within the larger 8K thing arena. That JSGCPageInfo contains a
+ * pointer to the 128 flag bytes corresponding to the things in the page, so we
+ * index into this flags array using the thing's index within its page.
+ *
+ * To align thing pages on 1024-byte boundaries, we must allocate the 9KB of
+ * flags+things arena payload, then find the first 0 mod 1024 boundary after
+ * the first payload address. That's where things start, with a JSGCPageInfo
+ * taking up the first thing-slot, as usual for 0 mod 1024 byte boundaries.
+ * The effect of this alignment trick is to split the flags into at most 2
+ * discontiguous spans, one before the things and one after (if we're really
+ * lucky, and the arena payload starts on a 0 mod 1024 byte boundary, no need
+ * to split).
+ *
+ * The overhead of this scheme for most platforms is (16+8*(8+1))/(16+9K) or
+ * .95% (assuming 16 byte JSArena header size, and 8 byte JSGCThing size).
+ *
+ * Here's some ASCII art showing an arena:
+ *
+ * split
+ * |
+ * V
+ * +--+-------+-------+-------+-------+-------+-------+-------+-------+-----+
+ * |fB| tp0 | tp1 | tp2 | tp3 | tp4 | tp5 | tp6 | tp7 | fA |
+ * +--+-------+-------+-------+-------+-------+-------+-------+-------+-----+
+ * ^ ^
+ * tI ---------+ |
+ * tJ -------------------------------------------+
+ *
+ * - fB are the "before split" flags, fA are the "after split" flags
+ * - tp0-tp7 are the 8 thing pages
+ * - thing tI points into tp1, whose flags are below the split, in fB
+ * - thing tJ points into tp5, clearly above the split
+ *
+ * In general, one of the thing pages will have some of its things' flags on
+ * the low side of the split, and the rest of its things' flags on the high
+ * side. All the other pages have flags only below or only above. Therefore
+ * we'll have to test something to decide whether the split divides flags in
+ * a given thing's page. So we store the split pointer (the pointer to tp0)
+ * in each JSGCPageInfo, along with the flags pointer for the 128 flag bytes
+ * ideally starting, for tp0 things, at the beginning of the arena's payload
+ * (at the start of fB).
+ *
+ * That is, each JSGCPageInfo's flags pointer is 128 bytes from the previous,
+ * or at the start of the arena if there is no previous page in this arena.
+ * Thus these ideal 128-byte flag pages run contiguously from the start of the
+ * arena (right over the split!), and the JSGCPageInfo flags pointers contain
+ * no discontinuities over the split created by the thing pages. So if, for a
+ * given JSGCPageInfo *pi, we find that
+ *
+ * pi->flags + ((jsuword)thing % 1024) / sizeof(JSGCThing) >= pi->split
+ *
+ * then we must add GC_THINGS_SIZE to the nominal flags pointer to jump over
+ * all the thing pages that split the flags into two discontiguous spans.
+ *
+ * (If we need to implement card-marking for an incremental GC write barrier,
+ * we can use the low byte of the pi->split pointer as the card-mark, for an
+ * extremely efficient write barrier: when mutating an object obj, just store
+ * a 1 byte at (uint8 *) ((jsuword)obj & ~1023) for little-endian platforms.
+ * When finding flags, we'll of course have to mask split with ~255, but it is
+ * guaranteed to be 1024-byte aligned, so no information is lost by overlaying
+ * the card-mark byte on split's low byte.)
+ */
+#define GC_PAGE_SHIFT 10
+#define GC_PAGE_MASK ((jsuword) JS_BITMASK(GC_PAGE_SHIFT))
+#define GC_PAGE_SIZE JS_BIT(GC_PAGE_SHIFT)
+
+typedef struct JSGCPageInfo {
+ uint8 *split;
+ uint8 *flags;
+} JSGCPageInfo;
+
+#define FIRST_THING_PAGE(a) (((a)->base + GC_FLAGS_SIZE) & ~GC_PAGE_MASK)
+
+static JSGCThing *
+gc_new_arena(JSArenaPool *pool)
+{
+ uint8 *flagp, *split, *pagep, *limit;
+ JSArena *a;
+ JSGCThing *thing;
+ JSGCPageInfo *pi;
+
+ /* Use JS_ArenaAllocate to grab another 9K-net-size hunk of space. */
+ flagp = (uint8 *) JS_ArenaAllocate(pool, GC_ARENA_SIZE);
+ if (!flagp)
+ return NULL;
+ a = pool->current;
+
+ /* Reset a->avail to start at the flags split, aka the first thing page. */
+ a->avail = FIRST_THING_PAGE(a);
+ split = pagep = (uint8 *) a->avail;
+ a->avail += sizeof(JSGCPageInfo);
+ thing = (JSGCThing *) a->avail;
+ a->avail += sizeof(JSGCThing);
+
+ /* Initialize the JSGCPageInfo records at the start of every thing page. */
+ limit = pagep + GC_THINGS_SIZE;
+ do {
+ pi = (JSGCPageInfo *) pagep;
+ pi->split = split;
+ pi->flags = flagp;
+ flagp += GC_PAGE_SIZE >> (GC_THINGS_SHIFT - GC_PAGE_SHIFT);
+ pagep += GC_PAGE_SIZE;
+ } while (pagep < limit);
+ return thing;
+}
+
+uint8 *
+js_GetGCThingFlags(void *thing)
+{
+ JSGCPageInfo *pi;
+ uint8 *flagp;
+
+ pi = (JSGCPageInfo *) ((jsuword)thing & ~GC_PAGE_MASK);
+ flagp = pi->flags + ((jsuword)thing & GC_PAGE_MASK) / sizeof(JSGCThing);
+ if (flagp >= pi->split)
+ flagp += GC_THINGS_SIZE;
+ return flagp;
+}
+
+JSBool
+js_IsAboutToBeFinalized(JSContext *cx, void *thing)
+{
+ uint8 flags = *js_GetGCThingFlags(thing);
+
+ return !(flags & (GCF_MARK | GCF_LOCKMASK | GCF_FINAL));
+}
+
+typedef void (*GCFinalizeOp)(JSContext *cx, JSGCThing *thing);
+
+static GCFinalizeOp gc_finalizers[GCX_NTYPES];
+
+intN
+js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
+ JSStringFinalizeOp newop)
+{
+ uintN i;
+
+ for (i = GCX_EXTERNAL_STRING; i < GCX_NTYPES; i++) {
+ if (gc_finalizers[i] == (GCFinalizeOp) oldop) {
+ gc_finalizers[i] = (GCFinalizeOp) newop;
+ return (intN) i;
+ }
+ }
+ return -1;
+}
+
+#ifdef JS_GCMETER
+#define METER(x) x
+#else
+#define METER(x) /* nothing */
+#endif
+
+/* Initial size of the gcRootsHash table (SWAG, small enough to amortize). */
+#define GC_ROOTS_SIZE 256
+#define GC_FINALIZE_LEN 1024
+
+JSBool
+js_InitGC(JSRuntime *rt, uint32 maxbytes)
+{
+ JS_ASSERT(sizeof(JSGCThing) == sizeof(JSGCPageInfo));
+ JS_ASSERT(sizeof(JSGCThing) >= sizeof(JSObject));
+ JS_ASSERT(sizeof(JSGCThing) >= sizeof(JSString));
+ JS_ASSERT(sizeof(JSGCThing) >= sizeof(jsdouble));
+ JS_ASSERT(GC_FLAGS_SIZE >= GC_PAGE_SIZE);
+ JS_ASSERT(sizeof(JSStackHeader) >= 2 * sizeof(jsval));
+
+ if (!gc_finalizers[GCX_OBJECT]) {
+ gc_finalizers[GCX_OBJECT] = (GCFinalizeOp)js_FinalizeObject;
+ gc_finalizers[GCX_STRING] = (GCFinalizeOp)js_FinalizeString;
+#ifdef DEBUG
+ gc_finalizers[GCX_DOUBLE] = (GCFinalizeOp)js_FinalizeDouble;
+#endif
+ gc_finalizers[GCX_MUTABLE_STRING] = (GCFinalizeOp)js_FinalizeString;
+ }
+
+ JS_InitArenaPool(&rt->gcArenaPool, "gc-arena", GC_ARENA_SIZE,
+ sizeof(JSGCThing));
+ if (!JS_DHashTableInit(&rt->gcRootsHash, JS_DHashGetStubOps(), NULL,
+ sizeof(JSGCRootHashEntry), GC_ROOTS_SIZE)) {
+ rt->gcRootsHash.ops = NULL;
+ return JS_FALSE;
+ }
+ rt->gcLocksHash = NULL; /* create lazily */
+ rt->gcMaxBytes = maxbytes;
+ return JS_TRUE;
+}
+
+#ifdef JS_GCMETER
+void
+js_DumpGCStats(JSRuntime *rt, FILE *fp)
+{
+ fprintf(fp, "\nGC allocation statistics:\n");
+ fprintf(fp, " bytes currently allocated: %lu\n", rt->gcBytes);
+ fprintf(fp, " alloc attempts: %lu\n", rt->gcStats.alloc);
+ fprintf(fp, " GC freelist length: %lu\n", rt->gcStats.freelen);
+ fprintf(fp, " recycles through GC freelist: %lu\n", rt->gcStats.recycle);
+ fprintf(fp, "alloc retries after running GC: %lu\n", rt->gcStats.retry);
+ fprintf(fp, " allocation failures: %lu\n", rt->gcStats.fail);
+ fprintf(fp, " valid lock calls: %lu\n", rt->gcStats.lock);
+ fprintf(fp, " valid unlock calls: %lu\n", rt->gcStats.unlock);
+ fprintf(fp, " locks that hit stuck counts: %lu\n", rt->gcStats.stuck);
+ fprintf(fp, " unlocks that saw stuck counts: %lu\n", rt->gcStats.unstuck);
+ fprintf(fp, " mark recursion depth: %lu\n", rt->gcStats.depth);
+ fprintf(fp, " maximum mark recursion depth: %lu\n", rt->gcStats.maxdepth);
+ fprintf(fp, " maximum GC nesting level: %lu\n", rt->gcStats.maxlevel);
+ fprintf(fp, " potentially useful GC calls: %lu\n", rt->gcStats.poke);
+ fprintf(fp, " useless GC calls: %lu\n", rt->gcStats.nopoke);
+ fprintf(fp, " thing arenas freed so far: %lu\n", rt->gcStats.afree);
+ fprintf(fp, " extra stack segments scanned: %lu\n", rt->gcStats.stackseg);
+ fprintf(fp, " stack segment slots scanned: %lu\n", rt->gcStats.segslots);
+#ifdef JS_ARENAMETER
+ JS_DumpArenaStats(fp);
+#endif
+}
+#endif
+
+#ifdef DEBUG
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_root_printer(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 i, void *arg)
+{
+ uint32 *leakedroots = (uint32 *)arg;
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
+
+ (*leakedroots)++;
+ fprintf(stderr,
+ "JS engine warning: leaking GC root \'%s\' at %p\n",
+ rhe->name ? (char *)rhe->name : "", rhe->root);
+
+ return JS_DHASH_NEXT;
+}
+#endif
+
+void
+js_FinishGC(JSRuntime *rt)
+{
+#ifdef JS_ARENAMETER
+ JS_DumpArenaStats(stdout);
+#endif
+#ifdef JS_GCMETER
+ js_DumpGCStats(rt, stdout);
+#endif
+ JS_FinishArenaPool(&rt->gcArenaPool);
+ JS_ArenaFinish();
+
+ if (rt->gcRootsHash.ops) {
+#ifdef DEBUG
+ uint32 leakedroots = 0;
+
+ /* Warn (but don't assert) debug builds of any remaining roots. */
+ JS_DHashTableEnumerate(&rt->gcRootsHash, js_root_printer,
+ &leakedroots);
+ if (leakedroots > 0) {
+ if (leakedroots == 1) {
+ fprintf(stderr,
+"JS engine warning: 1 GC root remains after destroying the JSRuntime.\n"
+" This root may point to freed memory. Objects reachable\n"
+" through it have not been finalized.\n");
+ } else {
+ fprintf(stderr,
+"JS engine warning: %lu GC roots remain after destroying the JSRuntime.\n"
+" These roots may point to freed memory. Objects reachable\n"
+" through them have not been finalized.\n",
+ (unsigned long) leakedroots);
+ }
+ }
+#endif
+
+ JS_DHashTableFinish(&rt->gcRootsHash);
+ rt->gcRootsHash.ops = NULL;
+ }
+ if (rt->gcLocksHash) {
+ JS_DHashTableDestroy(rt->gcLocksHash);
+ rt->gcLocksHash = NULL;
+ }
+ rt->gcFreeList = NULL;
+}
+
+JSBool
+js_AddRoot(JSContext *cx, void *rp, const char *name)
+{
+ JSBool ok = js_AddRootRT(cx->runtime, rp, name);
+ if (!ok)
+ JS_ReportOutOfMemory(cx);
+ return ok;
+}
+
+JSBool
+js_AddRootRT(JSRuntime *rt, void *rp, const char *name)
+{
+ JSBool ok;
+ JSGCRootHashEntry *rhe;
+
+ /*
+ * Due to the long-standing, but now removed, use of rt->gcLock across the
+ * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking
+ * properly with a racing GC, without calling JS_AddRoot from a request.
+ * We have to preserve API compatibility here, now that we avoid holding
+ * rt->gcLock across the mark phase (including the root hashtable mark).
+ *
+ * If the GC is running and we're called on another thread, wait for this
+ * GC activation to finish. We can safely wait here (in the case where we
+ * are called within a request on another thread's context) without fear
+ * of deadlock because the GC doesn't set rt->gcRunning until after it has
+ * waited for all active requests to end.
+ */
+ JS_LOCK_GC(rt);
+#ifdef JS_THREADSAFE
+ JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);
+ if (rt->gcRunning && rt->gcThread != js_CurrentThreadId()) {
+ do {
+ JS_AWAIT_GC_DONE(rt);
+ } while (rt->gcLevel > 0);
+ }
+#endif
+ rhe = (JSGCRootHashEntry *) JS_DHashTableOperate(&rt->gcRootsHash, rp,
+ JS_DHASH_ADD);
+ if (rhe) {
+ rhe->root = rp;
+ rhe->name = name;
+ ok = JS_TRUE;
+ } else {
+ ok = JS_FALSE;
+ }
+ JS_UNLOCK_GC(rt);
+ return ok;
+}
+
+JSBool
+js_RemoveRoot(JSRuntime *rt, void *rp)
+{
+ /*
+ * Due to the JS_RemoveRootRT API, we may be called outside of a request.
+ * Same synchronization drill as above in js_AddRoot.
+ */
+ JS_LOCK_GC(rt);
+#ifdef JS_THREADSAFE
+ JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);
+ if (rt->gcRunning && rt->gcThread != js_CurrentThreadId()) {
+ do {
+ JS_AWAIT_GC_DONE(rt);
+ } while (rt->gcLevel > 0);
+ }
+#endif
+ (void) JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_REMOVE);
+ rt->gcPoke = JS_TRUE;
+ JS_UNLOCK_GC(rt);
+ return JS_TRUE;
+}
+
+void *
+js_AllocGCThing(JSContext *cx, uintN flags)
+{
+ JSBool tried_gc;
+ JSRuntime *rt;
+ JSGCThing *thing;
+ uint8 *flagp;
+
+#ifdef TOO_MUCH_GC
+ js_GC(cx, GC_KEEP_ATOMS);
+ tried_gc = JS_TRUE;
+#else
+ tried_gc = JS_FALSE;
+#endif
+
+ rt = cx->runtime;
+ JS_LOCK_GC(rt);
+ JS_ASSERT(!rt->gcRunning);
+ if (rt->gcRunning) {
+ METER(rt->gcStats.finalfail++);
+ JS_UNLOCK_GC(rt);
+ return NULL;
+ }
+ METER(rt->gcStats.alloc++);
+retry:
+ thing = rt->gcFreeList;
+ if (thing) {
+ rt->gcFreeList = thing->next;
+ flagp = thing->flagp;
+ METER(rt->gcStats.freelen--);
+ METER(rt->gcStats.recycle++);
+ } else {
+ if (rt->gcBytes < rt->gcMaxBytes &&
+ (tried_gc || rt->gcMallocBytes < rt->gcMaxBytes))
+ {
+ /*
+ * Inline form of JS_ARENA_ALLOCATE adapted to truncate the current
+ * arena's limit to a GC_PAGE_SIZE boundary, and to skip over every
+ * GC_PAGE_SIZE-byte-aligned thing (which is actually not a thing,
+ * it's a JSGCPageInfo record).
+ */
+ JSArenaPool *pool = &rt->gcArenaPool;
+ JSArena *a = pool->current;
+ size_t nb = sizeof(JSGCThing);
+ jsuword p = a->avail;
+ jsuword q = p + nb;
+
+ if (q > (a->limit & ~GC_PAGE_MASK)) {
+ thing = gc_new_arena(pool);
+ } else {
+ if ((p & GC_PAGE_MASK) == 0) {
+ /* Beware, p points to a JSGCPageInfo record! */
+ p = q;
+ q += nb;
+ JS_ArenaCountAllocation(pool, nb);
+ }
+ a->avail = q;
+ thing = (JSGCThing *)p;
+ }
+ JS_ArenaCountAllocation(pool, nb);
+ }
+
+ /*
+ * Consider doing a "last ditch" GC if thing couldn't be allocated.
+ *
+ * Keep rt->gcLock across the call into js_GC so we don't starve and
+ * lose to racing threads who deplete the heap just after js_GC has
+ * replenished it (or has synchronized with a racing GC that collected
+ * a bunch of garbage). This unfair scheduling can happen on certain
+ * operating systems. For the gory details, see Mozilla bug 162779
+ * (http://bugzilla.mozilla.org/show_bug.cgi?id=162779).
+ */
+ if (!thing) {
+ if (!tried_gc) {
+ rt->gcPoke = JS_TRUE;
+ js_GC(cx, GC_KEEP_ATOMS | GC_ALREADY_LOCKED);
+ tried_gc = JS_TRUE;
+ METER(rt->gcStats.retry++);
+ goto retry;
+ }
+ METER(rt->gcStats.fail++);
+ JS_UNLOCK_GC(rt);
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+
+ /* Find the flags pointer given thing's address. */
+ flagp = js_GetGCThingFlags(thing);
+ }
+ *flagp = (uint8)flags;
+ rt->gcBytes += sizeof(JSGCThing) + sizeof(uint8);
+ cx->newborn[flags & GCF_TYPEMASK] = thing;
+
+ /*
+ * Clear thing before unlocking in case a GC run is about to scan it,
+ * finding it via cx->newborn[].
+ */
+ thing->next = NULL;
+ thing->flagp = NULL;
+ JS_UNLOCK_GC(rt);
+ return thing;
+}
+
+JSBool
+js_LockGCThing(JSContext *cx, void *thing)
+{
+ JSBool ok = js_LockGCThingRT(cx->runtime, thing);
+ if (!ok)
+ JS_ReportOutOfMemory(cx);
+ return ok;
+}
+
+JSBool
+js_LockGCThingRT(JSRuntime *rt, void *thing)
+{
+ uint8 *flagp, flags, lockbits;
+ JSBool ok;
+ JSGCLockHashEntry *lhe;
+
+ if (!thing)
+ return JS_TRUE;
+ flagp = js_GetGCThingFlags(thing);
+ flags = *flagp;
+
+ ok = JS_FALSE;
+ JS_LOCK_GC(rt);
+ lockbits = (flags & GCF_LOCKMASK);
+
+ if (lockbits != GCF_LOCKMASK) {
+ if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {
+ /* Objects may require "deep locking", i.e., rooting by value. */
+ if (lockbits == 0) {
+ if (!rt->gcLocksHash) {
+ rt->gcLocksHash =
+ JS_NewDHashTable(JS_DHashGetStubOps(), NULL,
+ sizeof(JSGCLockHashEntry),
+ GC_ROOTS_SIZE);
+ if (!rt->gcLocksHash)
+ goto error;
+ } else {
+#ifdef DEBUG
+ JSDHashEntryHdr *hdr =
+ JS_DHashTableOperate(rt->gcLocksHash, thing,
+ JS_DHASH_LOOKUP);
+ JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(hdr));
+#endif
+ }
+ lhe = (JSGCLockHashEntry *)
+ JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_ADD);
+ if (!lhe)
+ goto error;
+ lhe->thing = thing;
+ lhe->count = 1;
+ *flagp = (uint8)(flags + GCF_LOCK);
+ } else {
+ JS_ASSERT(lockbits == GCF_LOCK);
+ lhe = (JSGCLockHashEntry *)
+ JS_DHashTableOperate(rt->gcLocksHash, thing,
+ JS_DHASH_LOOKUP);
+ JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr));
+ if (JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr)) {
+ JS_ASSERT(lhe->count >= 1);
+ lhe->count++;
+ }
+ }
+ } else {
+ *flagp = (uint8)(flags + GCF_LOCK);
+ }
+ } else {
+ METER(rt->gcStats.stuck++);
+ }
+
+ METER(rt->gcStats.lock++);
+ ok = JS_TRUE;
+error:
+ JS_UNLOCK_GC(rt);
+ return ok;
+}
+
+JSBool
+js_UnlockGCThingRT(JSRuntime *rt, void *thing)
+{
+ uint8 *flagp, flags, lockbits;
+ JSGCLockHashEntry *lhe;
+
+ if (!thing)
+ return JS_TRUE;
+ flagp = js_GetGCThingFlags(thing);
+ flags = *flagp;
+
+ JS_LOCK_GC(rt);
+ lockbits = (flags & GCF_LOCKMASK);
+
+ if (lockbits != GCF_LOCKMASK) {
+ if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {
+ /* Defend against a call on an unlocked object. */
+ if (lockbits != 0) {
+ JS_ASSERT(lockbits == GCF_LOCK);
+ lhe = (JSGCLockHashEntry *)
+ JS_DHashTableOperate(rt->gcLocksHash, thing,
+ JS_DHASH_LOOKUP);
+ JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr));
+ if (JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr) &&
+ --lhe->count == 0) {
+ (void) JS_DHashTableOperate(rt->gcLocksHash, thing,
+ JS_DHASH_REMOVE);
+ *flagp = (uint8)(flags & ~GCF_LOCKMASK);
+ }
+ }
+ } else {
+ *flagp = (uint8)(flags - GCF_LOCK);
+ }
+ } else {
+ METER(rt->gcStats.unstuck++);
+ }
+
+ rt->gcPoke = JS_TRUE;
+ METER(rt->gcStats.unlock++);
+ JS_UNLOCK_GC(rt);
+ return JS_TRUE;
+}
+
+#ifdef GC_MARK_DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "jsprf.h"
+
+JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
+JS_EXPORT_DATA(void *) js_LiveThingToFind;
+
+#ifdef HAVE_XPCONNECT
+#include "dump_xpc.h"
+#endif
+
+static const char *
+gc_object_class_name(void* thing)
+{
+ uint8 *flagp = js_GetGCThingFlags(thing);
+ const char *className = "";
+ static char depbuf[32];
+
+ switch (*flagp & GCF_TYPEMASK) {
+ case GCX_OBJECT: {
+ JSObject *obj = (JSObject *)thing;
+ JSClass *clasp = JSVAL_TO_PRIVATE(obj->slots[JSSLOT_CLASS]);
+ className = clasp->name;
+#ifdef HAVE_XPCONNECT
+ if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
+ jsval privateValue = obj->slots[JSSLOT_PRIVATE];
+
+ JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE);
+ if (!JSVAL_IS_VOID(privateValue)) {
+ void *privateThing = JSVAL_TO_PRIVATE(privateValue);
+ const char *xpcClassName = GetXPCObjectClassName(privateThing);
+
+ if (xpcClassName)
+ className = xpcClassName;
+ }
+ }
+#endif
+ break;
+ }
+
+ case GCX_STRING:
+ case GCX_MUTABLE_STRING: {
+ JSString *str = (JSString *)thing;
+ if (JSSTRING_IS_DEPENDENT(str)) {
+ JS_snprintf(depbuf, sizeof depbuf, "start:%u, length:%u",
+ JSSTRDEP_START(str), JSSTRDEP_LENGTH(str));
+ className = depbuf;
+ } else {
+ className = "string";
+ }
+ break;
+ }
+
+ case GCX_DOUBLE:
+ className = "double";
+ break;
+ }
+
+ return className;
+}
+
+static void
+gc_dump_thing(JSGCThing *thing, uint8 flags, GCMarkNode *prev, FILE *fp)
+{
+ GCMarkNode *next = NULL;
+ char *path = NULL;
+
+ while (prev) {
+ next = prev;
+ prev = prev->prev;
+ }
+ while (next) {
+ path = JS_sprintf_append(path, "%s(%s).",
+ next->name,
+ gc_object_class_name(next->thing));
+ next = next->next;
+ }
+ if (!path)
+ return;
+
+ fprintf(fp, "%08lx ", (long)thing);
+ switch (flags & GCF_TYPEMASK) {
+ case GCX_OBJECT:
+ {
+ JSObject *obj = (JSObject *)thing;
+ jsval privateValue = obj->slots[JSSLOT_PRIVATE];
+ void *privateThing = JSVAL_IS_VOID(privateValue)
+ ? NULL
+ : JSVAL_TO_PRIVATE(privateValue);
+ const char *className = gc_object_class_name(thing);
+ fprintf(fp, "object %8p %s", privateThing, className);
+ break;
+ }
+ case GCX_DOUBLE:
+ fprintf(fp, "double %g", *(jsdouble *)thing);
+ break;
+ default:
+ fprintf(fp, "string %s", JS_GetStringBytes((JSString *)thing));
+ break;
+ }
+ fprintf(fp, " via %s\n", path);
+ free(path);
+}
+
+#endif /* !GC_MARK_DEBUG */
+
+static void
+gc_mark_atom_key_thing(void *thing, void *arg)
+{
+ JSContext *cx = (JSContext *) arg;
+
+ GC_MARK(cx, thing, "atom", NULL);
+}
+
+void
+js_MarkAtom(JSContext *cx, JSAtom *atom, void *arg)
+{
+ jsval key;
+
+ if (atom->flags & ATOM_MARK)
+ return;
+ atom->flags |= ATOM_MARK;
+ key = ATOM_KEY(atom);
+ if (JSVAL_IS_GCTHING(key)) {
+#ifdef GC_MARK_DEBUG
+ char name[32];
+
+ if (JSVAL_IS_STRING(key)) {
+ JS_snprintf(name, sizeof name, "'%s'",
+ JS_GetStringBytes(JSVAL_TO_STRING(key)));
+ } else {
+ JS_snprintf(name, sizeof name, "<%x>", key);
+ }
+#endif
+ GC_MARK(cx, JSVAL_TO_GCTHING(key), name, arg);
+ }
+}
+
+void
+js_MarkGCThing(JSContext *cx, void *thing, void *arg)
+{
+ uint8 flags, *flagp;
+ JSRuntime *rt;
+ JSObject *obj;
+ uint32 nslots;
+ jsval v, *vp, *end;
+ JSString *str;
+#ifdef GC_MARK_DEBUG
+ JSScope *scope;
+ JSScopeProperty *sprop;
+#endif
+
+ if (!thing)
+ return;
+
+ flagp = js_GetGCThingFlags(thing);
+ flags = *flagp;
+ JS_ASSERT(flags != GCF_FINAL);
+#ifdef GC_MARK_DEBUG
+ if (js_LiveThingToFind == thing)
+ gc_dump_thing(thing, flags, arg, stderr);
+#endif
+
+ if (flags & GCF_MARK)
+ return;
+
+ *flagp |= GCF_MARK;
+ rt = cx->runtime;
+ METER(if (++rt->gcStats.depth > rt->gcStats.maxdepth)
+ rt->gcStats.maxdepth = rt->gcStats.depth);
+
+#ifdef GC_MARK_DEBUG
+ if (js_DumpGCHeap)
+ gc_dump_thing(thing, flags, arg, js_DumpGCHeap);
+#endif
+
+ switch (flags & GCF_TYPEMASK) {
+ case GCX_OBJECT:
+ obj = (JSObject *) thing;
+ vp = obj->slots;
+ if (!vp) {
+ /* If obj->slots is null, obj must be a newborn. */
+ JS_ASSERT(!obj->map);
+ goto out;
+ }
+ nslots = (obj->map->ops->mark)
+ ? obj->map->ops->mark(cx, obj, arg)
+ : JS_MIN(obj->map->freeslot, obj->map->nslots);
+#ifdef GC_MARK_DEBUG
+ scope = OBJ_IS_NATIVE(obj) ? OBJ_SCOPE(obj) : NULL;
+#endif
+ for (end = vp + nslots; vp < end; vp++) {
+ v = *vp;
+ if (JSVAL_IS_GCTHING(v)) {
+#ifdef GC_MARK_DEBUG
+ char name[32];
+
+ if (scope) {
+ uint32 slot;
+ jsval nval;
+
+ slot = vp - obj->slots;
+ for (sprop = SCOPE_LAST_PROP(scope); ;
+ sprop = sprop->parent) {
+ if (!sprop) {
+ switch (slot) {
+ case JSSLOT_PROTO:
+ strcpy(name, "__proto__");
+ break;
+ case JSSLOT_PARENT:
+ strcpy(name, "__parent__");
+ break;
+ case JSSLOT_PRIVATE:
+ strcpy(name, "__private__");
+ break;
+ default:
+ JS_snprintf(name, sizeof name,
+ "**UNKNOWN SLOT %ld**",
+ (long)slot);
+ break;
+ }
+ break;
+ }
+ if (sprop->slot == slot) {
+ nval = ID_TO_VALUE(sprop->id);
+ if (JSVAL_IS_INT(nval)) {
+ JS_snprintf(name, sizeof name, "%ld",
+ (long)JSVAL_TO_INT(nval));
+ } else if (JSVAL_IS_STRING(nval)) {
+ JS_snprintf(name, sizeof name, "%s",
+ JS_GetStringBytes(JSVAL_TO_STRING(nval)));
+ } else {
+ strcpy(name, "**FINALIZED ATOM KEY**");
+ }
+ break;
+ }
+ }
+ } else {
+ strcpy(name, "**UNKNOWN OBJECT MAP ENTRY**");
+ }
+#endif
+ GC_MARK(cx, JSVAL_TO_GCTHING(v), name, arg);
+ }
+ }
+ break;
+
+#ifdef DEBUG
+ case GCX_STRING:
+ str = (JSString *)thing;
+ JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
+ break;
+#endif
+
+ case GCX_MUTABLE_STRING:
+ str = (JSString *)thing;
+ if (JSSTRING_IS_DEPENDENT(str))
+ GC_MARK(cx, JSSTRDEP_BASE(str), "base", arg);
+ break;
+ }
+
+out:
+ METER(rt->gcStats.depth--);
+}
+
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+gc_root_marker(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, void *arg)
+{
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
+ jsval *rp = (jsval *)rhe->root;
+ jsval v = *rp;
+
+ /* Ignore null object and scalar values. */
+ if (!JSVAL_IS_NULL(v) && JSVAL_IS_GCTHING(v)) {
+ JSContext *cx = (JSContext *)arg;
+#ifdef DEBUG
+ JSArena *a;
+ jsuword firstpage;
+ JSBool root_points_to_gcArenaPool = JS_FALSE;
+ void *thing = JSVAL_TO_GCTHING(v);
+
+ for (a = cx->runtime->gcArenaPool.first.next; a; a = a->next) {
+ firstpage = FIRST_THING_PAGE(a);
+ if (JS_UPTRDIFF(thing, firstpage) < a->avail - firstpage) {
+ root_points_to_gcArenaPool = JS_TRUE;
+ break;
+ }
+ }
+ if (!root_points_to_gcArenaPool && rhe->name) {
+ fprintf(stderr,
+"JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n"
+"invalid jsval. This is usually caused by a missing call to JS_RemoveRoot.\n"
+"The root's name is \"%s\".\n",
+ rhe->name);
+ }
+ JS_ASSERT(root_points_to_gcArenaPool);
+#endif
+
+ GC_MARK(cx, JSVAL_TO_GCTHING(v), rhe->name ? rhe->name : "root", NULL);
+ }
+ return JS_DHASH_NEXT;
+}
+
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+gc_lock_marker(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, void *arg)
+{
+ JSGCLockHashEntry *lhe = (JSGCLockHashEntry *)hdr;
+ void *thing = (void *)lhe->thing;
+ JSContext *cx = (JSContext *)arg;
+
+ GC_MARK(cx, thing, "locked object", NULL);
+ return JS_DHASH_NEXT;
+}
+
+void
+js_ForceGC(JSContext *cx, uintN gcflags)
+{
+ uintN i;
+
+ for (i = 0; i < GCX_NTYPES; i++)
+ cx->newborn[i] = NULL;
+ cx->lastAtom = NULL;
+ cx->runtime->gcPoke = JS_TRUE;
+ js_GC(cx, gcflags);
+ JS_ArenaFinish();
+}
+
+#define GC_MARK_JSVALS(cx, len, vec, name) \
+ JS_BEGIN_MACRO \
+ jsval _v, *_vp, *_end; \
+ \
+ for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \
+ _v = *_vp; \
+ if (JSVAL_IS_GCTHING(_v)) \
+ GC_MARK(cx, JSVAL_TO_GCTHING(_v), name, NULL); \
+ } \
+ JS_END_MACRO
+
+void
+js_GC(JSContext *cx, uintN gcflags)
+{
+ JSRuntime *rt;
+ JSContext *iter, *acx;
+ JSStackFrame *fp, *chain;
+ uintN i, depth, nslots, type;
+ JSStackHeader *sh;
+ JSArena *a, **ap;
+ uint8 flags, *flagp, *split;
+ JSGCThing *thing, *limit, **flp, **oflp;
+ GCFinalizeOp finalizer;
+ JSBool all_clear;
+#ifdef JS_THREADSAFE
+ jsword currentThread;
+ uint32 requestDebit;
+#endif
+
+ rt = cx->runtime;
+#ifdef JS_THREADSAFE
+ /* Avoid deadlock. */
+ JS_ASSERT(!JS_IS_RUNTIME_LOCKED(rt));
+#endif
+
+ /*
+ * Don't collect garbage if the runtime isn't up, and cx is not the last
+ * context in the runtime. The last context must force a GC, and nothing
+ * should suppress that final collection or there may be shutdown leaks,
+ * or runtime bloat until the next context is created.
+ */
+ if (rt->state != JSRTS_UP && !(gcflags & GC_LAST_CONTEXT))
+ return;
+
+ /*
+ * Let the API user decide to defer a GC if it wants to (unless this
+ * is the last context). Invoke the callback regardless.
+ */
+ if (rt->gcCallback) {
+ if (!rt->gcCallback(cx, JSGC_BEGIN) && !(gcflags & GC_LAST_CONTEXT))
+ return;
+ }
+
+ /* Lock out other GC allocator and collector invocations. */
+ if (!(gcflags & GC_ALREADY_LOCKED))
+ JS_LOCK_GC(rt);
+
+ /* Do nothing if no assignment has executed since the last GC. */
+ if (!rt->gcPoke) {
+ METER(rt->gcStats.nopoke++);
+ if (!(gcflags & GC_ALREADY_LOCKED))
+ JS_UNLOCK_GC(rt);
+ return;
+ }
+ METER(rt->gcStats.poke++);
+
+#ifdef JS_THREADSAFE
+ /* Bump gcLevel and return rather than nest on this thread. */
+ currentThread = js_CurrentThreadId();
+ if (rt->gcThread == currentThread) {
+ JS_ASSERT(rt->gcLevel > 0);
+ rt->gcLevel++;
+ METER(if (rt->gcLevel > rt->gcStats.maxlevel)
+ rt->gcStats.maxlevel = rt->gcLevel);
+ if (!(gcflags & GC_ALREADY_LOCKED))
+ JS_UNLOCK_GC(rt);
+ return;
+ }
+
+ /*
+ * If we're in one or more requests (possibly on more than one context)
+ * running on the current thread, indicate, temporarily, that all these
+ * requests are inactive. NB: if cx->thread is 0, then cx is not using
+ * the request model, and does not contribute to rt->requestCount.
+ */
+ requestDebit = 0;
+ if (cx->thread) {
+ /*
+ * Check all contexts for any with the same thread-id. XXX should we
+ * keep a sub-list of contexts having the same id?
+ */
+ iter = NULL;
+ while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
+ if (acx->thread == cx->thread && acx->requestDepth)
+ requestDebit++;
+ }
+ } else {
+ /*
+ * We assert, but check anyway, in case someone is misusing the API.
+ * Avoiding the loop over all of rt's contexts is a win in the event
+ * that the GC runs only on request-less contexts with 0 thread-ids,
+ * in a special thread such as might be used by the UI/DOM/Layout
+ * "mozilla" or "main" thread in Mozilla-the-browser.
+ */
+ JS_ASSERT(cx->requestDepth == 0);
+ if (cx->requestDepth)
+ requestDebit = 1;
+ }
+ if (requestDebit) {
+ JS_ASSERT(requestDebit <= rt->requestCount);
+ rt->requestCount -= requestDebit;
+ if (rt->requestCount == 0)
+ JS_NOTIFY_REQUEST_DONE(rt);
+ }
+
+ /* If another thread is already in GC, don't attempt GC; wait instead. */
+ if (rt->gcLevel > 0) {
+ /* Bump gcLevel to restart the current GC, so it finds new garbage. */
+ rt->gcLevel++;
+ METER(if (rt->gcLevel > rt->gcStats.maxlevel)
+ rt->gcStats.maxlevel = rt->gcLevel);
+
+ /* Wait for the other thread to finish, then resume our request. */
+ while (rt->gcLevel > 0)
+ JS_AWAIT_GC_DONE(rt);
+ if (requestDebit)
+ rt->requestCount += requestDebit;
+ if (!(gcflags & GC_ALREADY_LOCKED))
+ JS_UNLOCK_GC(rt);
+ return;
+ }
+
+ /* No other thread is in GC, so indicate that we're now in GC. */
+ rt->gcLevel = 1;
+ rt->gcThread = currentThread;
+
+ /* Wait for all other requests to finish. */
+ while (rt->requestCount > 0)
+ JS_AWAIT_REQUEST_DONE(rt);
+
+#else /* !JS_THREADSAFE */
+
+ /* Bump gcLevel and return rather than nest; the outer gc will restart. */
+ rt->gcLevel++;
+ METER(if (rt->gcLevel > rt->gcStats.maxlevel)
+ rt->gcStats.maxlevel = rt->gcLevel);
+ if (rt->gcLevel > 1)
+ return;
+
+#endif /* !JS_THREADSAFE */
+
+ /*
+ * Set rt->gcRunning here within the GC lock, and after waiting for any
+ * active requests to end, so that new requests that try to JS_AddRoot,
+ * JS_RemoveRoot, or JS_RemoveRootRT block in JS_BeginRequest waiting for
+ * rt->gcLevel to drop to zero, while request-less calls to the *Root*
+ * APIs block in js_AddRoot or js_RemoveRoot (see above in this file),
+ * waiting for GC to finish.
+ */
+ rt->gcRunning = JS_TRUE;
+ JS_UNLOCK_GC(rt);
+
+ /* If a suspended compile is running on another context, keep atoms. */
+ if (rt->gcKeepAtoms)
+ gcflags |= GC_KEEP_ATOMS;
+
+ /* Reset malloc counter. */
+ rt->gcMallocBytes = 0;
+
+ /* Drop atoms held by the property cache, and clear property weak links. */
+ js_DisablePropertyCache(cx);
+ js_FlushPropertyCache(cx);
+#ifdef DEBUG_brendan
+ { extern void js_DumpScopeMeters(JSRuntime *rt);
+ js_DumpScopeMeters(rt);
+ }
+#endif
+
+restart:
+ rt->gcNumber++;
+
+ /*
+ * Mark phase.
+ */
+ JS_DHashTableEnumerate(&rt->gcRootsHash, gc_root_marker, cx);
+ if (rt->gcLocksHash)
+ JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_marker, cx);
+ js_MarkAtomState(&rt->atomState, gcflags, gc_mark_atom_key_thing, cx);
+ js_MarkWatchPoints(rt);
+ iter = NULL;
+ while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {
+ /*
+ * Iterate frame chain and dormant chains. Temporarily tack current
+ * frame onto the head of the dormant list to ease iteration.
+ *
+ * (NB: see comment on this whole "dormant" thing in js_Execute.)
+ */
+ chain = acx->fp;
+ if (chain) {
+ JS_ASSERT(!chain->dormantNext);
+ chain->dormantNext = acx->dormantFrameChain;
+ } else {
+ chain = acx->dormantFrameChain;
+ }
+
+ for (fp = chain; fp; fp = chain = chain->dormantNext) {
+ do {
+ if (fp->callobj)
+ GC_MARK(cx, fp->callobj, "call object", NULL);
+ if (fp->argsobj)
+ GC_MARK(cx, fp->argsobj, "arguments object", NULL);
+ if (fp->varobj)
+ GC_MARK(cx, fp->varobj, "variables object", NULL);
+ if (fp->script) {
+ js_MarkScript(cx, fp->script, NULL);
+ if (fp->spbase) {
+ /*
+ * Don't mark what has not been pushed yet, or what
+ * has been popped already.
+ */
+ depth = fp->script->depth;
+ nslots = (JS_UPTRDIFF(fp->sp, fp->spbase)
+ < depth * sizeof(jsval))
+ ? (uintN)(fp->sp - fp->spbase)
+ : depth;
+ GC_MARK_JSVALS(cx, nslots, fp->spbase, "operand");
+ }
+ }
+ GC_MARK(cx, fp->thisp, "this", NULL);
+ if (fp->argv) {
+ nslots = fp->argc;
+ if (fp->fun && fp->fun->nargs > nslots)
+ nslots = fp->fun->nargs;
+ GC_MARK_JSVALS(cx, nslots, fp->argv, "arg");
+ }
+ if (JSVAL_IS_GCTHING(fp->rval))
+ GC_MARK(cx, JSVAL_TO_GCTHING(fp->rval), "rval", NULL);
+ if (fp->vars)
+ GC_MARK_JSVALS(cx, fp->nvars, fp->vars, "var");
+ GC_MARK(cx, fp->scopeChain, "scope chain", NULL);
+ if (fp->sharpArray)
+ GC_MARK(cx, fp->sharpArray, "sharp array", NULL);
+
+ if (fp->objAtomMap) {
+ JSAtom **vector, *atom;
+
+ nslots = fp->objAtomMap->length;
+ vector = fp->objAtomMap->vector;
+ for (i = 0; i < nslots; i++) {
+ atom = vector[i];
+ if (atom)
+ GC_MARK_ATOM(cx, atom, NULL);
+ }
+ }
+ } while ((fp = fp->down) != NULL);
+ }
+
+ /* Cleanup temporary "dormant" linkage. */
+ if (acx->fp)
+ acx->fp->dormantNext = NULL;
+
+ /* Mark other roots-by-definition in acx. */
+ GC_MARK(cx, acx->globalObject, "global object", NULL);
+ GC_MARK(cx, acx->newborn[GCX_OBJECT], "newborn object", NULL);
+ GC_MARK(cx, acx->newborn[GCX_STRING], "newborn string", NULL);
+ GC_MARK(cx, acx->newborn[GCX_DOUBLE], "newborn double", NULL);
+ GC_MARK(cx, acx->newborn[GCX_MUTABLE_STRING], "newborn mutable string",
+ NULL);
+ for (i = GCX_EXTERNAL_STRING; i < GCX_NTYPES; i++)
+ GC_MARK(cx, acx->newborn[i], "newborn external string", NULL);
+ if (acx->lastAtom)
+ GC_MARK_ATOM(cx, acx->lastAtom, NULL);
+#if JS_HAS_EXCEPTIONS
+ if (acx->throwing && JSVAL_IS_GCTHING(acx->exception))
+ GC_MARK(cx, JSVAL_TO_GCTHING(acx->exception), "exception", NULL);
+#endif
+#if JS_HAS_LVALUE_RETURN
+ if (acx->rval2set && JSVAL_IS_GCTHING(acx->rval2))
+ GC_MARK(cx, JSVAL_TO_GCTHING(acx->rval2), "rval2", NULL);
+#endif
+
+ for (sh = acx->stackHeaders; sh; sh = sh->down) {
+ METER(rt->gcStats.stackseg++);
+ METER(rt->gcStats.segslots += sh->nslots);
+ GC_MARK_JSVALS(cx, sh->nslots, JS_STACK_SEGMENT(sh), "stack");
+ }
+ }
+
+ if (rt->gcCallback)
+ (void) rt->gcCallback(cx, JSGC_MARK_END);
+
+ /*
+ * Sweep phase.
+ * Finalize as we sweep, outside of rt->gcLock, but with rt->gcRunning set
+ * so that any attempt to allocate a GC-thing from a finalizer will fail,
+ * rather than nest badly and leave the unmarked newborn to be swept.
+ */
+ js_SweepAtomState(&rt->atomState);
+ js_SweepScopeProperties(rt);
+ js_SweepScriptFilenames(rt);
+ for (a = rt->gcArenaPool.first.next; a; a = a->next) {
+ flagp = (uint8 *) a->base;
+ split = (uint8 *) FIRST_THING_PAGE(a);
+ limit = (JSGCThing *) a->avail;
+ for (thing = (JSGCThing *) split; thing < limit; thing++) {
+ if (((jsuword)thing & GC_PAGE_MASK) == 0) {
+ flagp++;
+ thing++;
+ }
+ flags = *flagp;
+ if (flags & GCF_MARK) {
+ *flagp &= ~GCF_MARK;
+ } else if (!(flags & (GCF_LOCKMASK | GCF_FINAL))) {
+ /* Call the finalizer with GCF_FINAL ORed into flags. */
+ type = flags & GCF_TYPEMASK;
+ finalizer = gc_finalizers[type];
+ if (finalizer) {
+ *flagp = (uint8)(flags | GCF_FINAL);
+ if (type >= GCX_EXTERNAL_STRING)
+ js_PurgeDeflatedStringCache((JSString *)thing);
+ finalizer(cx, thing);
+ }
+
+ /* Set flags to GCF_FINAL, signifying that thing is free. */
+ *flagp = GCF_FINAL;
+
+ JS_ASSERT(rt->gcBytes >= sizeof(JSGCThing) + sizeof(uint8));
+ rt->gcBytes -= sizeof(JSGCThing) + sizeof(uint8);
+ }
+ if (++flagp == split)
+ flagp += GC_THINGS_SIZE;
+ }
+ }
+
+ /*
+ * Free phase.
+ * Free any unused arenas and rebuild the JSGCThing freelist.
+ */
+ ap = &rt->gcArenaPool.first.next;
+ a = *ap;
+ if (!a)
+ goto out;
+ all_clear = JS_TRUE;
+ flp = oflp = &rt->gcFreeList;
+ *flp = NULL;
+ METER(rt->gcStats.freelen = 0);
+
+ do {
+ flagp = (uint8 *) a->base;
+ split = (uint8 *) FIRST_THING_PAGE(a);
+ limit = (JSGCThing *) a->avail;
+ for (thing = (JSGCThing *) split; thing < limit; thing++) {
+ if (((jsuword)thing & GC_PAGE_MASK) == 0) {
+ flagp++;
+ thing++;
+ }
+ if (*flagp != GCF_FINAL) {
+ all_clear = JS_FALSE;
+ } else {
+ thing->flagp = flagp;
+ *flp = thing;
+ flp = &thing->next;
+ METER(rt->gcStats.freelen++);
+ }
+ if (++flagp == split)
+ flagp += GC_THINGS_SIZE;
+ }
+
+ if (all_clear) {
+ JS_ARENA_DESTROY(&rt->gcArenaPool, a, ap);
+ flp = oflp;
+ METER(rt->gcStats.afree++);
+ } else {
+ ap = &a->next;
+ all_clear = JS_TRUE;
+ oflp = flp;
+ }
+ } while ((a = *ap) != NULL);
+
+ /* Terminate the new freelist. */
+ *flp = NULL;
+
+ if (rt->gcCallback)
+ (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
+#ifdef DEBUG_brendan
+ { extern void DumpSrcNoteSizeHist();
+ DumpSrcNoteSizeHist();
+ }
+#endif
+
+out:
+ JS_LOCK_GC(rt);
+ if (rt->gcLevel > 1) {
+ rt->gcLevel = 1;
+ JS_UNLOCK_GC(rt);
+ goto restart;
+ }
+ js_EnablePropertyCache(cx);
+ rt->gcLevel = 0;
+ rt->gcLastBytes = rt->gcBytes;
+ rt->gcPoke = rt->gcRunning = JS_FALSE;
+
+#ifdef JS_THREADSAFE
+ /* If we were invoked during a request, pay back the temporary debit. */
+ if (requestDebit)
+ rt->requestCount += requestDebit;
+ rt->gcThread = 0;
+ JS_NOTIFY_GC_DONE(rt);
+ if (!(gcflags & GC_ALREADY_LOCKED))
+ JS_UNLOCK_GC(rt);
+#endif
+
+ if (rt->gcCallback) {
+ if (gcflags & GC_ALREADY_LOCKED)
+ JS_UNLOCK_GC(rt);
+ (void) rt->gcCallback(cx, JSGC_END);
+ if (gcflags & GC_ALREADY_LOCKED)
+ JS_LOCK_GC(rt);
+ }
+}
diff --git a/src/dom/js/jsgc.h b/src/dom/js/jsgc.h
new file mode 100644
index 000000000..f501aca23
--- /dev/null
+++ b/src/dom/js/jsgc.h
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsgc_h___
+#define jsgc_h___
+/*
+ * JS Garbage Collector.
+ */
+#include "jsprvtd.h"
+#include "jspubtd.h"
+#include "jsdhash.h"
+
+JS_BEGIN_EXTERN_C
+
+/* GC thing type indexes. */
+#define GCX_OBJECT 0 /* JSObject */
+#define GCX_STRING 1 /* JSString */
+#define GCX_DOUBLE 2 /* jsdouble */
+#define GCX_MUTABLE_STRING 3 /* JSString that's mutable --
+ single-threaded only! */
+#define GCX_EXTERNAL_STRING 4 /* JSString w/ external chars */
+#define GCX_NTYPES_LOG2 3 /* type index bits */
+#define GCX_NTYPES JS_BIT(GCX_NTYPES_LOG2)
+
+/* GC flag definitions, must fit in 8 bits (type index goes in the low bits). */
+#define GCF_TYPEMASK JS_BITMASK(GCX_NTYPES_LOG2)
+#define GCF_MARK JS_BIT(GCX_NTYPES_LOG2)
+#define GCF_FINAL JS_BIT(GCX_NTYPES_LOG2 + 1)
+#define GCF_LOCKSHIFT (GCX_NTYPES_LOG2 + 2) /* lock bit shift and mask */
+#define GCF_LOCKMASK (JS_BITMASK(8 - GCF_LOCKSHIFT) << GCF_LOCKSHIFT)
+#define GCF_LOCK JS_BIT(GCF_LOCKSHIFT) /* lock request bit in API */
+
+/* Pseudo-flag that modifies GCX_STRING to make GCX_MUTABLE_STRING. */
+#define GCF_MUTABLE 2
+
+#if (GCX_STRING | GCF_MUTABLE) != GCX_MUTABLE_STRING
+# error "mutable string type index botch!"
+#endif
+
+extern uint8 *
+js_GetGCThingFlags(void *thing);
+
+/* These are compatible with JSDHashEntryStub. */
+struct JSGCRootHashEntry {
+ JSDHashEntryHdr hdr;
+ void *root;
+ const char *name;
+};
+
+struct JSGCLockHashEntry {
+ JSDHashEntryHdr hdr;
+ const JSGCThing *thing;
+ uint32 count;
+};
+
+#if 1
+/*
+ * Since we're forcing a GC from JS_GC anyway, don't bother wasting cycles
+ * loading oldval. XXX remove implied force, fix jsinterp.c's "second arg
+ * ignored", etc.
+ */
+#define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JS_TRUE)
+#else
+#define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JSVAL_IS_GCTHING(oldval))
+#endif
+
+extern intN
+js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
+ JSStringFinalizeOp newop);
+
+extern JSBool
+js_InitGC(JSRuntime *rt, uint32 maxbytes);
+
+extern void
+js_FinishGC(JSRuntime *rt);
+
+extern JSBool
+js_AddRoot(JSContext *cx, void *rp, const char *name);
+
+extern JSBool
+js_AddRootRT(JSRuntime *rt, void *rp, const char *name);
+
+extern JSBool
+js_RemoveRoot(JSRuntime *rt, void *rp);
+
+extern void *
+js_AllocGCThing(JSContext *cx, uintN flags);
+
+extern JSBool
+js_LockGCThing(JSContext *cx, void *thing);
+
+extern JSBool
+js_LockGCThingRT(JSRuntime *rt, void *thing);
+
+extern JSBool
+js_UnlockGCThingRT(JSRuntime *rt, void *thing);
+
+extern JSBool
+js_IsAboutToBeFinalized(JSContext *cx, void *thing);
+
+extern void
+js_MarkAtom(JSContext *cx, JSAtom *atom, void *arg);
+
+/* We avoid a large number of unnecessary calls by doing the flag check first */
+#define GC_MARK_ATOM(cx, atom, arg) \
+ JS_BEGIN_MACRO \
+ if (!((atom)->flags & ATOM_MARK)) \
+ js_MarkAtom(cx, atom, arg); \
+ JS_END_MACRO
+
+extern void
+js_MarkGCThing(JSContext *cx, void *thing, void *arg);
+
+#ifdef GC_MARK_DEBUG
+
+typedef struct GCMarkNode GCMarkNode;
+
+struct GCMarkNode {
+ void *thing;
+ const char *name;
+ GCMarkNode *next;
+ GCMarkNode *prev;
+};
+
+#define GC_MARK(_cx, _thing, _name, _prev) \
+ JS_BEGIN_MACRO \
+ GCMarkNode _node; \
+ _node.thing = _thing; \
+ _node.name = _name; \
+ _node.next = NULL; \
+ _node.prev = _prev; \
+ if (_prev) ((GCMarkNode *)(_prev))->next = &_node; \
+ js_MarkGCThing(_cx, _thing, &_node); \
+ JS_END_MACRO
+
+#else /* !GC_MARK_DEBUG */
+
+#define GC_MARK(cx, thing, name, prev) js_MarkGCThing(cx, thing, NULL)
+
+#endif /* !GC_MARK_DEBUG */
+
+/*
+ * Flags to modify how a GC marks and sweeps:
+ * GC_KEEP_ATOMS Don't sweep unmarked atoms, they may be in use by the
+ * compiler, or by an API function that calls js_Atomize,
+ * when the GC is called from js_AllocGCThing, due to a
+ * malloc failure or runtime GC-thing limit.
+ * GC_LAST_CONTEXT Called from js_DestroyContext for last JSContext in a
+ * JSRuntime, when it is imperative that rt->gcPoke gets
+ * cleared early in js_GC, if it is set.
+ * GC_ALREADY_LOCKED rt->gcLock is already held on entry to js_GC, and kept
+ * on return to its caller.
+ */
+#define GC_KEEP_ATOMS 0x1
+#define GC_LAST_CONTEXT 0x2
+#define GC_ALREADY_LOCKED 0x4
+
+extern void
+js_ForceGC(JSContext *cx, uintN gcflags);
+
+extern void
+js_GC(JSContext *cx, uintN gcflags);
+
+#ifdef JS_GCMETER
+
+typedef struct JSGCStats {
+ uint32 alloc; /* number of allocation attempts */
+ uint32 freelen; /* gcFreeList length */
+ uint32 recycle; /* number of things recycled through gcFreeList */
+ uint32 retry; /* allocation attempt retries after running the GC */
+ uint32 fail; /* allocation failures */
+ uint32 finalfail; /* finalizer calls allocator failures */
+ uint32 lock; /* valid lock calls */
+ uint32 unlock; /* valid unlock calls */
+ uint32 stuck; /* stuck reference counts seen by lock calls */
+ uint32 unstuck; /* unlock calls that saw a stuck lock count */
+ uint32 depth; /* mark recursion depth */
+ uint32 maxdepth; /* maximum mark recursion depth */
+ uint32 maxlevel; /* maximum GC nesting (indirect recursion) level */
+ uint32 poke; /* number of potentially useful GC calls */
+ uint32 nopoke; /* useless GC calls where js_PokeGC was not set */
+ uint32 afree; /* thing arenas freed so far */
+ uint32 stackseg; /* total extraordinary stack segments scanned */
+ uint32 segslots; /* total stack segment jsval slots scanned */
+} JSGCStats;
+
+extern void
+js_DumpGCStats(JSRuntime *rt, FILE *fp);
+
+#endif /* JS_GCMETER */
+
+JS_END_EXTERN_C
+
+#endif /* jsgc_h___ */
diff --git a/src/dom/js/jshash.c b/src/dom/js/jshash.c
new file mode 100644
index 000000000..3382daadb
--- /dev/null
+++ b/src/dom/js/jshash.c
@@ -0,0 +1,479 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * PR hash table package.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsbit.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jshash.h" /* Added by JSIFY */
+
+/* Compute the number of buckets in ht */
+#define NBUCKETS(ht) JS_BIT(JS_HASH_BITS - (ht)->shift)
+
+/* The smallest table has 16 buckets */
+#define MINBUCKETSLOG2 4
+#define MINBUCKETS JS_BIT(MINBUCKETSLOG2)
+
+/* Compute the maximum entries given n buckets that we will tolerate, ~90% */
+#define OVERLOADED(n) ((n) - ((n) >> 3))
+
+/* Compute the number of entries below which we shrink the table by half */
+#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
+
+/*
+** Stubs for default hash allocator ops.
+*/
+static void *
+DefaultAllocTable(void *pool, size_t size)
+{
+ return malloc(size);
+}
+
+static void
+DefaultFreeTable(void *pool, void *item)
+{
+ free(item);
+}
+
+static JSHashEntry *
+DefaultAllocEntry(void *pool, const void *key)
+{
+ return (JSHashEntry*) malloc(sizeof(JSHashEntry));
+}
+
+static void
+DefaultFreeEntry(void *pool, JSHashEntry *he, uintN flag)
+{
+ if (flag == HT_FREE_ENTRY)
+ free(he);
+}
+
+static JSHashAllocOps defaultHashAllocOps = {
+ DefaultAllocTable, DefaultFreeTable,
+ DefaultAllocEntry, DefaultFreeEntry
+};
+
+JS_PUBLIC_API(JSHashTable *)
+JS_NewHashTable(uint32 n, JSHashFunction keyHash,
+ JSHashComparator keyCompare, JSHashComparator valueCompare,
+ JSHashAllocOps *allocOps, void *allocPriv)
+{
+ JSHashTable *ht;
+ size_t nb;
+
+ if (n <= MINBUCKETS) {
+ n = MINBUCKETSLOG2;
+ } else {
+ n = JS_CeilingLog2(n);
+ if ((int32)n < 0)
+ return NULL;
+ }
+
+ if (!allocOps) allocOps = &defaultHashAllocOps;
+
+ ht = (JSHashTable*) (*allocOps->allocTable)(allocPriv, sizeof *ht);
+ if (!ht)
+ return NULL;
+ memset(ht, 0, sizeof *ht);
+ ht->shift = JS_HASH_BITS - n;
+ n = JS_BIT(n);
+#if defined _MSC_VER && _MSC_VER <= 800
+ if (n > 16000) {
+ (*allocOps->freeTable)(allocPriv, ht);
+ return NULL;
+ }
+#endif /* WIN16 */
+ nb = n * sizeof(JSHashEntry *);
+ ht->buckets = (JSHashEntry**) (*allocOps->allocTable)(allocPriv, nb);
+ if (!ht->buckets) {
+ (*allocOps->freeTable)(allocPriv, ht);
+ return NULL;
+ }
+ memset(ht->buckets, 0, nb);
+
+ ht->keyHash = keyHash;
+ ht->keyCompare = keyCompare;
+ ht->valueCompare = valueCompare;
+ ht->allocOps = allocOps;
+ ht->allocPriv = allocPriv;
+ return ht;
+}
+
+JS_PUBLIC_API(void)
+JS_HashTableDestroy(JSHashTable *ht)
+{
+ uint32 i, n;
+ JSHashEntry *he, **hep;
+ JSHashAllocOps *allocOps = ht->allocOps;
+ void *allocPriv = ht->allocPriv;
+
+ n = NBUCKETS(ht);
+ for (i = 0; i < n; i++) {
+ hep = &ht->buckets[i];
+ while ((he = *hep) != NULL) {
+ *hep = he->next;
+ (*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY);
+ }
+ }
+#ifdef DEBUG
+ memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
+#endif
+ (*allocOps->freeTable)(allocPriv, ht->buckets);
+#ifdef DEBUG
+ memset(ht, 0xDB, sizeof *ht);
+#endif
+ (*allocOps->freeTable)(allocPriv, ht);
+}
+
+/*
+** Multiplicative hash, from Knuth 6.4.
+*/
+JS_PUBLIC_API(JSHashEntry **)
+JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key)
+{
+ JSHashEntry *he, **hep, **hep0;
+ JSHashNumber h;
+
+#ifdef HASHMETER
+ ht->nlookups++;
+#endif
+ h = keyHash * JS_GOLDEN_RATIO;
+ h >>= ht->shift;
+ hep = hep0 = &ht->buckets[h];
+ while ((he = *hep) != NULL) {
+ if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) {
+ /* Move to front of chain if not already there */
+ if (hep != hep0) {
+ *hep = he->next;
+ he->next = *hep0;
+ *hep0 = he;
+ }
+ return hep0;
+ }
+ hep = &he->next;
+#ifdef HASHMETER
+ ht->nsteps++;
+#endif
+ }
+ return hep;
+}
+
+JS_PUBLIC_API(JSHashEntry *)
+JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep,
+ JSHashNumber keyHash, const void *key, void *value)
+{
+ uint32 i, n;
+ JSHashEntry *he, *next, **oldbuckets;
+ size_t nb;
+
+ /* Grow the table if it is overloaded */
+ n = NBUCKETS(ht);
+ if (ht->nentries >= OVERLOADED(n)) {
+ oldbuckets = ht->buckets;
+#if defined _MSC_VER && _MSC_VER <= 800
+ if (2 * n > 16000)
+ return NULL;
+#endif /* WIN16 */
+ nb = 2 * n * sizeof(JSHashEntry *);
+ ht->buckets = (JSHashEntry**) (*ht->allocOps->allocTable)(ht->allocPriv, nb);
+ if (!ht->buckets) {
+ ht->buckets = oldbuckets;
+ return NULL;
+ }
+ memset(ht->buckets, 0, nb);
+#ifdef HASHMETER
+ ht->ngrows++;
+#endif
+ ht->shift--;
+
+ for (i = 0; i < n; i++) {
+ for (he = oldbuckets[i]; he; he = next) {
+ next = he->next;
+ hep = JS_HashTableRawLookup(ht, he->keyHash, he->key);
+ JS_ASSERT(*hep == NULL);
+ he->next = NULL;
+ *hep = he;
+ }
+ }
+#ifdef DEBUG
+ memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
+#endif
+ (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ }
+
+ /* Make a new key value entry */
+ he = (*ht->allocOps->allocEntry)(ht->allocPriv, key);
+ if (!he)
+ return NULL;
+ he->keyHash = keyHash;
+ he->key = key;
+ he->value = value;
+ he->next = *hep;
+ *hep = he;
+ ht->nentries++;
+ return he;
+}
+
+JS_PUBLIC_API(JSHashEntry *)
+JS_HashTableAdd(JSHashTable *ht, const void *key, void *value)
+{
+ JSHashNumber keyHash;
+ JSHashEntry *he, **hep;
+
+ keyHash = (*ht->keyHash)(key);
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ if ((he = *hep) != NULL) {
+ /* Hit; see if values match */
+ if ((*ht->valueCompare)(he->value, value)) {
+ /* key,value pair is already present in table */
+ return he;
+ }
+ if (he->value)
+ (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE);
+ he->value = value;
+ return he;
+ }
+ return JS_HashTableRawAdd(ht, hep, keyHash, key, value);
+}
+
+JS_PUBLIC_API(void)
+JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he)
+{
+ uint32 i, n;
+ JSHashEntry *next, **oldbuckets;
+ size_t nb;
+
+ *hep = he->next;
+ (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY);
+
+ /* Shrink table if it's underloaded */
+ n = NBUCKETS(ht);
+ if (--ht->nentries < UNDERLOADED(n)) {
+ oldbuckets = ht->buckets;
+ nb = n * sizeof(JSHashEntry*) / 2;
+ ht->buckets = (JSHashEntry**) (*ht->allocOps->allocTable)(ht->allocPriv, nb);
+ if (!ht->buckets) {
+ ht->buckets = oldbuckets;
+ return;
+ }
+ memset(ht->buckets, 0, nb);
+#ifdef HASHMETER
+ ht->nshrinks++;
+#endif
+ ht->shift++;
+
+ for (i = 0; i < n; i++) {
+ for (he = oldbuckets[i]; he; he = next) {
+ next = he->next;
+ hep = JS_HashTableRawLookup(ht, he->keyHash, he->key);
+ JS_ASSERT(*hep == NULL);
+ he->next = NULL;
+ *hep = he;
+ }
+ }
+#ifdef DEBUG
+ memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
+#endif
+ (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
+ }
+}
+
+JS_PUBLIC_API(JSBool)
+JS_HashTableRemove(JSHashTable *ht, const void *key)
+{
+ JSHashNumber keyHash;
+ JSHashEntry *he, **hep;
+
+ keyHash = (*ht->keyHash)(key);
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ if ((he = *hep) == NULL)
+ return JS_FALSE;
+
+ /* Hit; remove element */
+ JS_HashTableRawRemove(ht, hep, he);
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(void *)
+JS_HashTableLookup(JSHashTable *ht, const void *key)
+{
+ JSHashNumber keyHash;
+ JSHashEntry *he, **hep;
+
+ keyHash = (*ht->keyHash)(key);
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ if ((he = *hep) != NULL) {
+ return he->value;
+ }
+ return NULL;
+}
+
+/*
+** Iterate over the entries in the hash table calling func for each
+** entry found. Stop if "f" says to (return value & JS_ENUMERATE_STOP).
+** Return a count of the number of elements scanned.
+*/
+JS_PUBLIC_API(int)
+JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg)
+{
+ JSHashEntry *he, **hep;
+ uint32 i, nbuckets;
+ int rv, n = 0;
+ JSHashEntry *todo = NULL;
+
+ nbuckets = NBUCKETS(ht);
+ for (i = 0; i < nbuckets; i++) {
+ hep = &ht->buckets[i];
+ while ((he = *hep) != NULL) {
+ rv = (*f)(he, n, arg);
+ n++;
+ if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) {
+ *hep = he->next;
+ if (rv & HT_ENUMERATE_REMOVE) {
+ he->next = todo;
+ todo = he;
+ }
+ } else {
+ hep = &he->next;
+ }
+ if (rv & HT_ENUMERATE_STOP) {
+ goto out;
+ }
+ }
+ }
+
+out:
+ hep = &todo;
+ while ((he = *hep) != NULL) {
+ JS_HashTableRawRemove(ht, hep, he);
+ }
+ return n;
+}
+
+#ifdef HASHMETER
+#include <math.h>
+#include <stdio.h>
+
+JS_PUBLIC_API(void)
+JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
+{
+ double sqsum, mean, variance, sigma;
+ uint32 nchains, nbuckets, nentries;
+ uint32 i, n, maxChain, maxChainLen;
+ JSHashEntry *he;
+
+ sqsum = 0;
+ nchains = 0;
+ maxChainLen = 0;
+ nbuckets = NBUCKETS(ht);
+ for (i = 0; i < nbuckets; i++) {
+ he = ht->buckets[i];
+ if (!he)
+ continue;
+ nchains++;
+ for (n = 0; he; he = he->next)
+ n++;
+ sqsum += n * n;
+ if (n > maxChainLen) {
+ maxChainLen = n;
+ maxChain = i;
+ }
+ }
+ nentries = ht->nentries;
+ mean = (double)nentries / nchains;
+ variance = nchains * sqsum - nentries * nentries;
+ if (variance < 0 || nchains == 1)
+ variance = 0;
+ else
+ variance /= nchains * (nchains - 1);
+ sigma = sqrt(variance);
+
+ fprintf(fp, "\nHash table statistics:\n");
+ fprintf(fp, " number of lookups: %u\n", ht->nlookups);
+ fprintf(fp, " number of entries: %u\n", ht->nentries);
+ fprintf(fp, " number of grows: %u\n", ht->ngrows);
+ fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
+ fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
+ / ht->nlookups);
+ fprintf(fp, "mean hash chain length: %g\n", mean);
+ fprintf(fp, " standard deviation: %g\n", sigma);
+ fprintf(fp, " max hash chain length: %u\n", maxChainLen);
+ fprintf(fp, " max hash chain: [%u]\n", maxChain);
+
+ for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
+ if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT)
+ break;
+}
+#endif /* HASHMETER */
+
+JS_PUBLIC_API(int)
+JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
+{
+ int count;
+
+ count = JS_HashTableEnumerateEntries(ht, dump, fp);
+#ifdef HASHMETER
+ JS_HashTableDumpMeter(ht, dump, fp);
+#endif
+ return count;
+}
+
+JS_PUBLIC_API(JSHashNumber)
+JS_HashString(const void *key)
+{
+ JSHashNumber h;
+ const unsigned char *s;
+
+ h = 0;
+ for (s = (const unsigned char *)key; *s; s++)
+ h = (h >> (JS_HASH_BITS - 4)) ^ (h << 4) ^ *s;
+ return h;
+}
+
+JS_PUBLIC_API(int)
+JS_CompareValues(const void *v1, const void *v2)
+{
+ return v1 == v2;
+}
diff --git a/src/dom/js/jshash.h b/src/dom/js/jshash.h
new file mode 100644
index 000000000..85e3cf811
--- /dev/null
+++ b/src/dom/js/jshash.h
@@ -0,0 +1,152 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jshash_h___
+#define jshash_h___
+/*
+ * API to portable hash table code.
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include "jstypes.h"
+#include "jscompat.h"
+
+JS_BEGIN_EXTERN_C
+
+typedef uint32 JSHashNumber;
+typedef struct JSHashEntry JSHashEntry;
+typedef struct JSHashTable JSHashTable;
+
+#define JS_HASH_BITS 32
+#define JS_GOLDEN_RATIO 0x9E3779B9U
+
+typedef JSHashNumber (* JS_DLL_CALLBACK JSHashFunction)(const void *key);
+typedef intN (* JS_DLL_CALLBACK JSHashComparator)(const void *v1, const void *v2);
+typedef intN (* JS_DLL_CALLBACK JSHashEnumerator)(JSHashEntry *he, intN i, void *arg);
+
+/* Flag bits in JSHashEnumerator's return value */
+#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */
+#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */
+#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */
+#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */
+
+typedef struct JSHashAllocOps {
+ void * (*allocTable)(void *pool, size_t size);
+ void (*freeTable)(void *pool, void *item);
+ JSHashEntry * (*allocEntry)(void *pool, const void *key);
+ void (*freeEntry)(void *pool, JSHashEntry *he, uintN flag);
+} JSHashAllocOps;
+
+#define HT_FREE_VALUE 0 /* just free the entry's value */
+#define HT_FREE_ENTRY 1 /* free value and entire entry */
+
+struct JSHashEntry {
+ JSHashEntry *next; /* hash chain linkage */
+ JSHashNumber keyHash; /* key hash function result */
+ const void *key; /* ptr to opaque key */
+ void *value; /* ptr to opaque value */
+};
+
+struct JSHashTable {
+ JSHashEntry **buckets; /* vector of hash buckets */
+ uint32 nentries; /* number of entries in table */
+ uint32 shift; /* multiplicative hash shift */
+ JSHashFunction keyHash; /* key hash function */
+ JSHashComparator keyCompare; /* key comparison function */
+ JSHashComparator valueCompare; /* value comparison function */
+ JSHashAllocOps *allocOps; /* allocation operations */
+ void *allocPriv; /* allocation private data */
+#ifdef HASHMETER
+ uint32 nlookups; /* total number of lookups */
+ uint32 nsteps; /* number of hash chains traversed */
+ uint32 ngrows; /* number of table expansions */
+ uint32 nshrinks; /* number of table contractions */
+#endif
+};
+
+/*
+ * Create a new hash table.
+ * If allocOps is null, use default allocator ops built on top of malloc().
+ */
+extern JS_PUBLIC_API(JSHashTable *)
+JS_NewHashTable(uint32 n, JSHashFunction keyHash,
+ JSHashComparator keyCompare, JSHashComparator valueCompare,
+ JSHashAllocOps *allocOps, void *allocPriv);
+
+extern JS_PUBLIC_API(void)
+JS_HashTableDestroy(JSHashTable *ht);
+
+/* Low level access methods */
+extern JS_PUBLIC_API(JSHashEntry **)
+JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key);
+
+extern JS_PUBLIC_API(JSHashEntry *)
+JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep, JSHashNumber keyHash,
+ const void *key, void *value);
+
+extern JS_PUBLIC_API(void)
+JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he);
+
+/* Higher level access methods */
+extern JS_PUBLIC_API(JSHashEntry *)
+JS_HashTableAdd(JSHashTable *ht, const void *key, void *value);
+
+extern JS_PUBLIC_API(JSBool)
+JS_HashTableRemove(JSHashTable *ht, const void *key);
+
+extern JS_PUBLIC_API(intN)
+JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg);
+
+extern JS_PUBLIC_API(void *)
+JS_HashTableLookup(JSHashTable *ht, const void *key);
+
+extern JS_PUBLIC_API(intN)
+JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp);
+
+/* General-purpose C string hash function. */
+extern JS_PUBLIC_API(JSHashNumber)
+JS_HashString(const void *key);
+
+/* Stub function just returns v1 == v2 */
+extern JS_PUBLIC_API(intN)
+JS_CompareValues(const void *v1, const void *v2);
+
+JS_END_EXTERN_C
+
+#endif /* jshash_h___ */
diff --git a/src/dom/js/jsinterp.c b/src/dom/js/jsinterp.c
new file mode 100644
index 000000000..60f39b3ce
--- /dev/null
+++ b/src/dom/js/jsinterp.c
@@ -0,0 +1,4284 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* build on macs with low memory */
+#if defined(XP_MAC) && defined(MOZ_MAC_LOWMEM)
+#pragma optimization_level 1
+#endif
+
+/*
+ * JavaScript bytecode interpreter.
+ */
+#include "jsstddef.h"
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdbgapi.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+#if JS_HAS_JIT
+#include "jsjit.h"
+#endif
+
+#ifdef DEBUG
+#define ASSERT_CACHE_IS_EMPTY(cache) \
+ JS_BEGIN_MACRO \
+ JSPropertyCacheEntry *end_, *pce_, entry_; \
+ JSPropertyCache *cache_ = (cache); \
+ JS_ASSERT(cache_->empty); \
+ end_ = &cache_->table[PROPERTY_CACHE_SIZE]; \
+ for (pce_ = &cache_->table[0]; pce_ < end_; pce_++) { \
+ PCE_LOAD(cache_, pce_, entry_); \
+ JS_ASSERT(!PCE_OBJECT(entry_)); \
+ JS_ASSERT(!PCE_PROPERTY(entry_)); \
+ } \
+ JS_END_MACRO
+#else
+#define ASSERT_CACHE_IS_EMPTY(cache) ((void)0)
+#endif
+
+void
+js_FlushPropertyCache(JSContext *cx)
+{
+ JSPropertyCache *cache;
+
+ cache = &cx->runtime->propertyCache;
+ if (cache->empty) {
+ ASSERT_CACHE_IS_EMPTY(cache);
+ return;
+ }
+ memset(cache->table, 0, sizeof cache->table);
+ cache->empty = JS_TRUE;
+#ifdef JS_PROPERTY_CACHE_METERING
+ cache->flushes++;
+#endif
+}
+
+void
+js_DisablePropertyCache(JSContext *cx)
+{
+ JS_ASSERT(!cx->runtime->propertyCache.disabled);
+ cx->runtime->propertyCache.disabled = JS_TRUE;
+}
+
+void
+js_EnablePropertyCache(JSContext *cx)
+{
+ JS_ASSERT(cx->runtime->propertyCache.disabled);
+ ASSERT_CACHE_IS_EMPTY(&cx->runtime->propertyCache);
+ cx->runtime->propertyCache.disabled = JS_FALSE;
+}
+
+/*
+ * Class for for/in loop property iterator objects.
+ */
+#define JSSLOT_ITER_STATE JSSLOT_PRIVATE
+
+static void
+prop_iterator_finalize(JSContext *cx, JSObject *obj)
+{
+ jsval iter_state;
+ jsval iteratee;
+
+ /* Protect against stillborn iterators. */
+ iter_state = obj->slots[JSSLOT_ITER_STATE];
+ iteratee = obj->slots[JSSLOT_PARENT];
+ if (!JSVAL_IS_NULL(iter_state) && !JSVAL_IS_PRIMITIVE(iteratee)) {
+ OBJ_ENUMERATE(cx, JSVAL_TO_OBJECT(iteratee), JSENUMERATE_DESTROY,
+ &iter_state, NULL);
+ }
+ js_RemoveRoot(cx->runtime, &obj->slots[JSSLOT_PARENT]);
+
+ /* XXX force the GC to restart so we can collect iteratee, if possible,
+ during the current collector activation */
+ cx->runtime->gcLevel++;
+}
+
+static JSClass prop_iterator_class = {
+ "PropertyIterator",
+ 0,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iterator_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+/*
+ * Stack macros and functions. These all use a local variable, jsval *sp, to
+ * point to the next free stack slot. SAVE_SP must be called before any call
+ * to a function that may invoke the interpreter. RESTORE_SP must be called
+ * only after return from js_Invoke, because only js_Invoke changes fp->sp.
+ */
+#define PUSH(v) (*sp++ = (v))
+#define POP() (*--sp)
+#ifdef DEBUG
+#define SAVE_SP(fp) \
+ (JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase), \
+ (fp)->sp = sp)
+#else
+#define SAVE_SP(fp) ((fp)->sp = sp)
+#endif
+#define RESTORE_SP(fp) (sp = (fp)->sp)
+
+/*
+ * Push the generating bytecode's pc onto the parallel pc stack that runs
+ * depth slots below the operands.
+ *
+ * NB: PUSH_OPND uses sp, depth, and pc from its lexical environment. See
+ * js_Interpret for these local variables' declarations and uses.
+ */
+#define PUSH_OPND(v) (sp[-depth] = (jsval)pc, PUSH(v))
+#define STORE_OPND(n,v) (sp[(n)-depth] = (jsval)pc, sp[n] = (v))
+#define POP_OPND() POP()
+#define FETCH_OPND(n) (sp[n])
+
+/*
+ * Push the jsdouble d using sp, depth, and pc from the lexical environment.
+ * Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
+ * for it and push a reference.
+ */
+#define STORE_NUMBER(cx, n, d) \
+ JS_BEGIN_MACRO \
+ jsint i_; \
+ jsval v_; \
+ \
+ if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) { \
+ v_ = INT_TO_JSVAL(i_); \
+ } else { \
+ ok = js_NewDoubleValue(cx, d, &v_); \
+ if (!ok) \
+ goto out; \
+ } \
+ STORE_OPND(n, v_); \
+ JS_END_MACRO
+
+#define FETCH_NUMBER(cx, n, d) \
+ JS_BEGIN_MACRO \
+ jsval v_; \
+ \
+ v_ = FETCH_OPND(n); \
+ VALUE_TO_NUMBER(cx, v_, d); \
+ JS_END_MACRO
+
+#define FETCH_INT(cx, n, i) \
+ JS_BEGIN_MACRO \
+ jsval v_ = FETCH_OPND(n); \
+ if (JSVAL_IS_INT(v_)) { \
+ i = JSVAL_TO_INT(v_); \
+ } else { \
+ SAVE_SP(fp); \
+ ok = js_ValueToECMAInt32(cx, v_, &i); \
+ if (!ok) \
+ goto out; \
+ } \
+ JS_END_MACRO
+
+#define FETCH_UINT(cx, n, ui) \
+ JS_BEGIN_MACRO \
+ jsval v_ = FETCH_OPND(n); \
+ jsint i_; \
+ if (JSVAL_IS_INT(v_) && (i_ = JSVAL_TO_INT(v_)) >= 0) { \
+ ui = (uint32) i_; \
+ } else { \
+ SAVE_SP(fp); \
+ ok = js_ValueToECMAUint32(cx, v_, &ui); \
+ if (!ok) \
+ goto out; \
+ } \
+ JS_END_MACRO
+
+/*
+ * Optimized conversion macros that test for the desired type in v before
+ * homing sp and calling a conversion function.
+ */
+#define VALUE_TO_NUMBER(cx, v, d) \
+ JS_BEGIN_MACRO \
+ if (JSVAL_IS_INT(v)) { \
+ d = (jsdouble)JSVAL_TO_INT(v); \
+ } else if (JSVAL_IS_DOUBLE(v)) { \
+ d = *JSVAL_TO_DOUBLE(v); \
+ } else { \
+ SAVE_SP(fp); \
+ ok = js_ValueToNumber(cx, v, &d); \
+ if (!ok) \
+ goto out; \
+ } \
+ JS_END_MACRO
+
+#define POP_BOOLEAN(cx, v, b) \
+ JS_BEGIN_MACRO \
+ v = FETCH_OPND(-1); \
+ if (v == JSVAL_NULL) { \
+ b = JS_FALSE; \
+ } else if (JSVAL_IS_BOOLEAN(v)) { \
+ b = JSVAL_TO_BOOLEAN(v); \
+ } else { \
+ SAVE_SP(fp); \
+ ok = js_ValueToBoolean(cx, v, &b); \
+ if (!ok) \
+ goto out; \
+ } \
+ sp--; \
+ JS_END_MACRO
+
+#define VALUE_TO_OBJECT(cx, v, obj) \
+ JS_BEGIN_MACRO \
+ if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) { \
+ obj = JSVAL_TO_OBJECT(v); \
+ } else { \
+ SAVE_SP(fp); \
+ obj = js_ValueToNonNullObject(cx, v); \
+ if (!obj) { \
+ ok = JS_FALSE; \
+ goto out; \
+ } \
+ } \
+ JS_END_MACRO
+
+#if JS_BUG_VOID_TOSTRING
+#define CHECK_VOID_TOSTRING(cx, v) \
+ if (JSVAL_IS_VOID(v)) { \
+ JSString *str_; \
+ str_ = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); \
+ v = STRING_TO_JSVAL(str_); \
+ }
+#else
+#define CHECK_VOID_TOSTRING(cx, v) ((void)0)
+#endif
+
+#if JS_BUG_EAGER_TOSTRING
+#define CHECK_EAGER_TOSTRING(hint) (hint = JSTYPE_STRING)
+#else
+#define CHECK_EAGER_TOSTRING(hint) ((void)0)
+#endif
+
+#define VALUE_TO_PRIMITIVE(cx, v, hint, vp) \
+ JS_BEGIN_MACRO \
+ if (JSVAL_IS_PRIMITIVE(v)) { \
+ CHECK_VOID_TOSTRING(cx, v); \
+ *vp = v; \
+ } else { \
+ SAVE_SP(fp); \
+ CHECK_EAGER_TOSTRING(hint); \
+ ok = OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, vp); \
+ if (!ok) \
+ goto out; \
+ } \
+ JS_END_MACRO
+
+JS_FRIEND_API(jsval *)
+js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
+{
+ jsval *sp;
+
+ if (markp)
+ *markp = JS_ARENA_MARK(&cx->stackPool);
+ JS_ARENA_ALLOCATE_CAST(sp, jsval *, &cx->stackPool, nslots * sizeof(jsval));
+ if (!sp) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_STACK_OVERFLOW,
+ (cx->fp && cx->fp->fun)
+ ? JS_GetFunctionName(cx->fp->fun)
+ : "script");
+ }
+ return sp;
+}
+
+JS_FRIEND_API(void)
+js_FreeRawStack(JSContext *cx, void *mark)
+{
+ JS_ARENA_RELEASE(&cx->stackPool, mark);
+}
+
+JS_FRIEND_API(jsval *)
+js_AllocStack(JSContext *cx, uintN nslots, void **markp)
+{
+ jsval *sp, *vp, *end;
+ JSArena *a;
+ JSStackHeader *sh;
+ JSStackFrame *fp;
+
+ /* Callers don't check for zero nslots: we do to avoid empty segments. */
+ if (nslots == 0) {
+ *markp = NULL;
+ return JS_ARENA_MARK(&cx->stackPool);
+ }
+
+ /* Allocate 2 extra slots for the stack segment header we'll likely need. */
+ sp = js_AllocRawStack(cx, 2 + nslots, markp);
+ if (!sp)
+ return NULL;
+
+ /* Try to avoid another header if we can piggyback on the last segment. */
+ a = cx->stackPool.current;
+ sh = cx->stackHeaders;
+ if (sh && JS_STACK_SEGMENT(sh) + sh->nslots == sp) {
+ /* Extend the last stack segment, give back the 2 header slots. */
+ sh->nslots += nslots;
+ a->avail -= 2 * sizeof(jsval);
+ } else {
+ /*
+ * Need a new stack segment, so we must initialize unused slots in the
+ * current frame. See js_GC, just before marking the "operand" jsvals,
+ * where we scan from fp->spbase to fp->sp or through fp->script->depth
+ * (whichever covers fewer slots).
+ */
+ fp = cx->fp;
+ if (fp && fp->script && fp->spbase) {
+#ifdef DEBUG
+ jsuword depthdiff = fp->script->depth * sizeof(jsval);
+ JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= depthdiff);
+ JS_ASSERT(JS_UPTRDIFF(*markp, fp->spbase) >= depthdiff);
+#endif
+ end = fp->spbase + fp->script->depth;
+ for (vp = fp->sp; vp < end; vp++)
+ *vp = JSVAL_VOID;
+ }
+
+ /* Allocate and push a stack segment header from the 2 extra slots. */
+ sh = (JSStackHeader *)sp;
+ sh->nslots = nslots;
+ sh->down = cx->stackHeaders;
+ cx->stackHeaders = sh;
+ sp += 2;
+ }
+
+ return sp;
+}
+
+JS_FRIEND_API(void)
+js_FreeStack(JSContext *cx, void *mark)
+{
+ JSStackHeader *sh;
+ jsuword slotdiff;
+
+ /* Check for zero nslots allocation special case. */
+ if (!mark)
+ return;
+
+ /* We can assert because js_FreeStack always balances js_AllocStack. */
+ sh = cx->stackHeaders;
+ JS_ASSERT(sh);
+
+ /* If mark is in the current segment, reduce sh->nslots, else pop sh. */
+ slotdiff = JS_UPTRDIFF(mark, JS_STACK_SEGMENT(sh)) / sizeof(jsval);
+ if (slotdiff < (jsuword)sh->nslots)
+ sh->nslots = slotdiff;
+ else
+ cx->stackHeaders = sh->down;
+
+ /* Release the stackPool space allocated since mark was set. */
+ JS_ARENA_RELEASE(&cx->stackPool, mark);
+}
+
+/*
+ * To economize on slots space in functions, the compiler records arguments and
+ * local variables as shared (JSPROP_SHARED) properties with well-known getters
+ * and setters: js_{Get,Set}Argument, js_{Get,Set}LocalVariable. Now, we could
+ * record args and vars in lists or hash tables in function-private data, but
+ * that means more duplication in code, and more data at runtime in the hash
+ * table case due to round-up to powers of two, just to recapitulate the scope
+ * machinery in the function object.
+ *
+ * What's more, for a long time (to the dawn of "Mocha" in 1995), these getters
+ * and setters knew how to search active stack frames in a context to find the
+ * top activation of the function f, in order to satisfy a get or set of f.a,
+ * for argument a, or f.x, for local variable x. You could use f.a instead of
+ * just a in function f(a) { return f.a }, for example, to return the actual
+ * parameter.
+ *
+ * ECMA requires that we give up on this ancient extension, because it is not
+ * compatible with the standard as used by real-world scripts. While Chapter
+ * 16 does allow for additional properties to be defined on native objects by
+ * a conforming implementation, these magic getters and setters cause f.a's
+ * meaning to vary unexpectedly. Real-world scripts set f.A = 42 to define
+ * "class static" (after Java) constants, for example, but if A also names an
+ * arg or var in f, the constant is not available while f is active, and any
+ * non-constant class-static can't be set while f is active.
+ *
+ * So, to label arg and var properties in functions without giving them magic
+ * abilities to affect active frame stack slots, while keeping the properties
+ * shared (slot-less) to save space in the common case (where no assignment
+ * sets a function property with the same name as an arg or var), the setters
+ * for args and vars must handle two special cases here.
+ *
+ * XXX functions tend to have few args and vars, so we risk O(n^2) growth here
+ * XXX ECMA *really* wants args and vars to be stored in function-private data,
+ * not as function object properties.
+ */
+static JSBool
+SetFunctionSlot(JSContext *cx, JSObject *obj, JSPropertyOp setter, jsid id,
+ jsval v)
+{
+ uintN slot;
+ JSObject *origobj;
+ JSScope *scope;
+ JSScopeProperty *sprop;
+ JSString *str;
+ JSBool ok;
+
+ slot = (uintN) JSVAL_TO_INT(id);
+ if (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
+ /*
+ * Given a non-function object obj that has a function object in its
+ * prototype chain, where an argument or local variable property named
+ * by (setter, slot) is being set, override the shared property in the
+ * prototype with an unshared property in obj. This situation arises
+ * in real-world JS due to .prototype setting and collisions among a
+ * function's "static property" names and arg or var names, believe it
+ * or not.
+ */
+ origobj = obj;
+ do {
+ obj = OBJ_GET_PROTO(cx, obj);
+ if (!obj)
+ return JS_TRUE;
+ } while (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass);
+
+ JS_LOCK_OBJ(cx, obj);
+ scope = OBJ_SCOPE(obj);
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (sprop->setter == setter) {
+ JS_ASSERT(!JSVAL_IS_INT(sprop->id) &&
+ ATOM_IS_STRING((JSAtom *)sprop->id) &&
+ (sprop->flags & SPROP_HAS_SHORTID));
+
+ if ((uintN) sprop->shortid == slot) {
+ str = ATOM_TO_STRING((JSAtom *)sprop->id);
+ JS_UNLOCK_SCOPE(cx, scope);
+
+ return JS_DefineUCProperty(cx, origobj,
+ JSSTRING_CHARS(str),
+ JSSTRING_LENGTH(str),
+ v, NULL, NULL,
+ JSPROP_ENUMERATE);
+ }
+ }
+ }
+ JS_UNLOCK_SCOPE(cx, scope);
+ return JS_TRUE;
+ }
+
+ /*
+ * Argument and local variable properties of function objects are shared
+ * by default (JSPROP_SHARED), therefore slot-less. But if for function
+ * f(a) {}, f.a = 42 is evaluated, f.a should be 42 after the assignment,
+ * whether or not f is active. So js_SetArgument and js_SetLocalVariable
+ * must be prepared to change an arg or var from shared to unshared status,
+ * allocating a slot in obj to hold v.
+ */
+ ok = JS_TRUE;
+ JS_LOCK_OBJ(cx, obj);
+ scope = OBJ_SCOPE(obj);
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (sprop->setter == setter && (uintN) sprop->shortid == slot) {
+ if (sprop->attrs & JSPROP_SHARED) {
+ sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,
+ 0, ~JSPROP_SHARED,
+ sprop->getter, setter);
+ if (!sprop) {
+ ok = JS_FALSE;
+ } else {
+ /* See js_SetProperty, near the bottom. */
+ GC_POKE(cx, pval);
+ LOCKED_OBJ_SET_SLOT(obj, sprop->slot, v);
+ }
+ }
+ break;
+ }
+ }
+ JS_UNLOCK_SCOPE(cx, scope);
+ return ok;
+}
+
+JSBool
+js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ return JS_TRUE;
+}
+
+JSBool
+js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ return SetFunctionSlot(cx, obj, js_SetArgument, id, *vp);
+}
+
+JSBool
+js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ return JS_TRUE;
+}
+
+JSBool
+js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ return SetFunctionSlot(cx, obj, js_SetLocalVariable, id, *vp);
+}
+
+/*
+ * Compute the 'this' parameter and store it in frame as frame.thisp.
+ * Activation objects ("Call" objects not created with "new Call()", i.e.,
+ * "Call" objects that have private data) may not be referred to by 'this',
+ * as dictated by ECMA.
+ *
+ * N.B.: fp->argv must be set, fp->argv[-1] the nominal 'this' paramter as
+ * a jsval, and fp->argv[-2] must be the callee object reference, usually a
+ * function object. Also, fp->flags must contain JSFRAME_CONSTRUCTING if we
+ * are preparing for a constructor call.
+ */
+static JSBool
+ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp)
+{
+ JSObject *parent;
+
+ if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) {
+ /* Some objects (e.g., With) delegate 'this' to another object. */
+ thisp = OBJ_THIS_OBJECT(cx, thisp);
+ if (!thisp)
+ return JS_FALSE;
+
+ /* Default return value for a constructor is the new object. */
+ if (fp->flags & JSFRAME_CONSTRUCTING)
+ fp->rval = OBJECT_TO_JSVAL(thisp);
+ } else {
+ /*
+ * ECMA requires "the global object", but in the presence of multiple
+ * top-level objects (windows, frames, or certain layers in the client
+ * object model), we prefer fun's parent. An example that causes this
+ * code to run:
+ *
+ * // in window w1
+ * function f() { return this }
+ * function g() { return f }
+ *
+ * // in window w2
+ * var h = w1.g()
+ * alert(h() == w1)
+ *
+ * The alert should display "true".
+ */
+ JS_ASSERT(!(fp->flags & JSFRAME_CONSTRUCTING));
+ if (JSVAL_IS_PRIMITIVE(fp->argv[-2]) ||
+ !(parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2])))) {
+ thisp = cx->globalObject;
+ } else {
+ /* walk up to find the top-level object */
+ thisp = parent;
+ while ((parent = OBJ_GET_PARENT(cx, thisp)) != NULL)
+ thisp = parent;
+ }
+ }
+ fp->thisp = thisp;
+ fp->argv[-1] = OBJECT_TO_JSVAL(thisp);
+ return JS_TRUE;
+}
+
+/*
+ * Find a function reference and its 'this' object implicit first parameter
+ * under argc arguments on cx's stack, and call the function. Push missing
+ * required arguments, allocate declared local variables, and pop everything
+ * when done. Then push the return value.
+ */
+JS_FRIEND_API(JSBool)
+js_Invoke(JSContext *cx, uintN argc, uintN flags)
+{
+ void *mark;
+ JSStackFrame *fp, frame;
+ jsval *sp, *newsp, *limit;
+ jsval *vp, v;
+ JSObject *funobj, *parent, *thisp;
+ JSBool ok;
+ JSClass *clasp;
+ JSObjectOps *ops;
+ JSNative native;
+ JSFunction *fun;
+ JSScript *script;
+ uintN minargs, nvars;
+ intN nslots, nalloc, surplus;
+ JSInterpreterHook hook;
+ void *hookData;
+
+ /* Mark the top of stack and load frequently-used registers. */
+ mark = JS_ARENA_MARK(&cx->stackPool);
+ fp = cx->fp;
+ sp = fp->sp;
+
+ /*
+ * Set vp to the callee value's stack slot (it's where rval goes).
+ * Once vp is set, control should flow through label out2: to return.
+ * Set frame.rval early so native class and object ops can throw and
+ * return false, causing a goto out2 with ok set to false. Also set
+ * frame.flags to flags so that ComputeThis can test bits in it.
+ */
+ vp = sp - (2 + argc);
+ v = *vp;
+ frame.rval = JSVAL_VOID;
+ frame.flags = flags;
+ thisp = JSVAL_TO_OBJECT(vp[1]);
+
+ /*
+ * A callee must be an object reference, unless its |this| parameter
+ * implements the __noSuchMethod__ method, in which case that method will
+ * be called like so:
+ *
+ * thisp.__noSuchMethod__(id, args)
+ *
+ * where id is the name of the method that this invocation attempted to
+ * call by name, and args is an Array containing this invocation's actual
+ * parameters.
+ */
+ if (JSVAL_IS_PRIMITIVE(v)) {
+#if JS_HAS_NO_SUCH_METHOD
+ jsbytecode *pc;
+ jsatomid atomIndex;
+ JSAtom *atom;
+ JSObject *argsobj;
+ JSArena *a;
+
+ if (!fp->script || (flags & JSINVOKE_INTERNAL))
+ goto bad;
+
+ /*
+ * We must ComputeThis here to censor Call objects; performance hit,
+ * but at least it's idempotent.
+ *
+ * Normally, we call ComputeThis after all frame members have been
+ * set, and in particular, after any revision of the callee value at
+ * *vp due to clasp->convert (see below). This matters because
+ * ComputeThis may access *vp via fp->argv[-2], to follow the parent
+ * chain to a global object to use as the |this| parameter.
+ *
+ * Obviously, here in the JSVAL_IS_PRIMITIVE(v) case, there can't be
+ * any such defaulting of |this| to callee (v, *vp) ancestor.
+ */
+ frame.argv = vp + 2;
+ ok = ComputeThis(cx, thisp, &frame);
+ if (!ok)
+ goto out2;
+ thisp = frame.thisp;
+
+ ok = OBJ_GET_PROPERTY(cx, thisp,
+ (jsid)cx->runtime->atomState.noSuchMethodAtom,
+ &v);
+ if (!ok)
+ goto out2;
+ if (JSVAL_IS_PRIMITIVE(v))
+ goto bad;
+
+ pc = (jsbytecode *) vp[-(intN)fp->script->depth];
+ switch ((JSOp) *pc) {
+ case JSOP_NAME:
+ case JSOP_GETPROP:
+ atomIndex = GET_ATOM_INDEX(pc);
+ atom = js_GetAtom(cx, &fp->script->atomMap, atomIndex);
+ argsobj = js_NewArrayObject(cx, argc, vp + 2);
+ if (!argsobj) {
+ ok = JS_FALSE;
+ goto out2;
+ }
+
+ sp = vp + 4;
+ if (argc < 2) {
+ a = cx->stackPool.current;
+ if ((jsuword)sp > a->limit) {
+ /*
+ * Arguments must be contiguous, and must include argv[-1]
+ * and argv[-2], so allocate more stack, advance sp, and
+ * set newsp[1] to thisp (vp[1]). The other argv elements
+ * will be set below, using negative indexing from sp.
+ */
+ newsp = js_AllocRawStack(cx, 4, NULL);
+ if (!newsp) {
+ ok = JS_FALSE;
+ goto out2;
+ }
+ newsp[1] = OBJECT_TO_JSVAL(thisp);
+ sp = newsp + 4;
+ } else if ((jsuword)sp > a->avail) {
+ /*
+ * Inline, optimized version of JS_ARENA_ALLOCATE to claim
+ * the small number of words not already allocated as part
+ * of the caller's operand stack.
+ */
+ JS_ArenaCountAllocation(pool, (jsuword)sp - a->avail);
+ a->avail = (jsuword)sp;
+ }
+ }
+
+ sp[-4] = v;
+ JS_ASSERT(sp[-3] == OBJECT_TO_JSVAL(thisp));
+ sp[-2] = ATOM_KEY(atom);
+ sp[-1] = OBJECT_TO_JSVAL(argsobj);
+ fp->sp = sp;
+ argc = 2;
+ break;
+
+ default:
+ goto bad;
+ }
+#else
+ goto bad;
+#endif
+ }
+
+ funobj = JSVAL_TO_OBJECT(v);
+ parent = OBJ_GET_PARENT(cx, funobj);
+ clasp = OBJ_GET_CLASS(cx, funobj);
+ if (clasp != &js_FunctionClass) {
+ /* Function is inlined, all other classes use object ops. */
+ ops = funobj->map->ops;
+
+ /*
+ * XXX
+ * Try converting to function, for closure and API compatibility.
+ * We attempt the conversion under all circumstances for 1.2, but
+ * only if there is a call op defined otherwise.
+ */
+ if (cx->version == JSVERSION_1_2 ||
+ ((ops == &js_ObjectOps) ? clasp->call : ops->call)) {
+ ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);
+ if (!ok)
+ goto out2;
+
+ if (JSVAL_IS_FUNCTION(cx, v)) {
+ /* Make vp refer to funobj to keep it available as argv[-2]. */
+ *vp = v;
+ funobj = JSVAL_TO_OBJECT(v);
+ parent = OBJ_GET_PARENT(cx, funobj);
+ goto have_fun;
+ }
+ }
+ fun = NULL;
+ script = NULL;
+ minargs = nvars = 0;
+
+ /* Try a call or construct native object op. */
+ native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call;
+ if (!native)
+ goto bad;
+ } else {
+have_fun:
+ /* Get private data and set derived locals from it. */
+ fun = (JSFunction *) JS_GetPrivate(cx, funobj);
+ native = fun->native;
+ script = fun->script;
+ minargs = fun->nargs + fun->extra;
+ nvars = fun->nvars;
+
+ /* Handle bound method special case. */
+ if (fun->flags & JSFUN_BOUND_METHOD)
+ thisp = parent;
+ }
+
+ /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */
+ frame.varobj = NULL;
+ frame.callobj = frame.argsobj = NULL;
+ frame.script = script;
+ frame.fun = fun;
+ frame.argc = argc;
+ frame.argv = sp - argc;
+ frame.nvars = nvars;
+ frame.vars = sp;
+ frame.down = fp;
+ frame.annotation = NULL;
+ frame.scopeChain = NULL; /* set below for real, after cx->fp is set */
+ frame.pc = NULL;
+ frame.spbase = NULL;
+ frame.sharpDepth = 0;
+ frame.sharpArray = NULL;
+ frame.dormantNext = NULL;
+ frame.objAtomMap = NULL;
+
+ /* Compute the 'this' parameter and store it in frame as frame.thisp. */
+ ok = ComputeThis(cx, thisp, &frame);
+ if (!ok)
+ goto out2;
+
+ /* From here on, control must flow through label out: to return. */
+ cx->fp = &frame;
+
+ /* Init these now in case we goto out before first hook call. */
+ hook = cx->runtime->callHook;
+ hookData = NULL;
+
+ /* Check for missing arguments expected by the function. */
+ nslots = (intN)((argc < minargs) ? minargs - argc : 0);
+ if (nslots) {
+ /* All arguments must be contiguous, so we may have to copy actuals. */
+ nalloc = nslots;
+ limit = (jsval *) cx->stackPool.current->limit;
+ if (sp + nslots > limit) {
+ /* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */
+ nalloc += 2 + argc;
+ } else {
+ /* Take advantage of surplus slots in the caller's frame depth. */
+ surplus = (jsval *)mark - sp;
+ JS_ASSERT(surplus >= 0);
+ nalloc -= surplus;
+ }
+
+ /* Check whether we have enough space in the caller's frame. */
+ if (nalloc > 0) {
+ /* Need space for actuals plus missing formals minus surplus. */
+ newsp = js_AllocRawStack(cx, (uintN)nalloc, NULL);
+ if (!newsp) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ /* If we couldn't allocate contiguous args, copy actuals now. */
+ if (newsp != mark) {
+ JS_ASSERT(sp + nslots > limit);
+ JS_ASSERT(2 + argc + nslots == (uintN)nalloc);
+ *newsp++ = vp[0];
+ *newsp++ = vp[1];
+ if (argc)
+ memcpy(newsp, frame.argv, argc * sizeof(jsval));
+ frame.argv = newsp;
+ sp = frame.vars = newsp + argc;
+ }
+ }
+
+ /* Advance frame.vars to make room for the missing args. */
+ frame.vars += nslots;
+
+ /* Push void to initialize missing args. */
+ while (--nslots >= 0)
+ PUSH(JSVAL_VOID);
+ }
+
+ /* Now allocate stack space for local variables. */
+ nslots = (intN)frame.nvars;
+ if (nslots) {
+ surplus = (intN)((jsval *)cx->stackPool.current->avail - frame.vars);
+ if (surplus < nslots) {
+ newsp = js_AllocRawStack(cx, (uintN)nslots, NULL);
+ if (!newsp) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ if (newsp != sp) {
+ /* NB: Discontinuity between argv and vars. */
+ sp = frame.vars = newsp;
+ }
+ }
+
+ /* Push void to initialize local variables. */
+ while (--nslots >= 0)
+ PUSH(JSVAL_VOID);
+ }
+
+ /* Store the current sp in frame before calling fun. */
+ SAVE_SP(&frame);
+
+ /* call the hook if present */
+ if (hook && (native || script))
+ hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->callHookData);
+
+ /* Call the function, either a native method or an interpreted script. */
+ if (native) {
+#if JS_HAS_LVALUE_RETURN
+ /* Set by JS_SetCallReturnValue2, used to return reference types. */
+ cx->rval2set = JS_FALSE;
+#endif
+
+ /* If native, use caller varobj and scopeChain for eval. */
+ frame.varobj = fp->varobj;
+ frame.scopeChain = fp->scopeChain;
+ ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);
+ JS_RUNTIME_METER(cx->runtime, nativeCalls);
+ } else if (script) {
+ /* Use parent scope so js_GetCallObject can find the right "Call". */
+ frame.scopeChain = parent;
+ if (fun->flags & JSFUN_HEAVYWEIGHT) {
+#if JS_HAS_CALL_OBJECT
+ /* Scope with a call object parented by the callee's parent. */
+ if (!js_GetCallObject(cx, &frame, parent)) {
+ ok = JS_FALSE;
+ goto out;
+ }
+#else
+ /* Bad old code used the function as a proxy for all calls to it. */
+ frame.scopeChain = funobj;
+#endif
+ }
+ ok = js_Interpret(cx, &v);
+ } else {
+ /* fun might be onerror trying to report a syntax error in itself. */
+ frame.scopeChain = NULL;
+ ok = JS_TRUE;
+ }
+
+out:
+ if (hookData) {
+ hook = cx->runtime->callHook;
+ if (hook)
+ hook(cx, &frame, JS_FALSE, &ok, hookData);
+ }
+#if JS_HAS_CALL_OBJECT
+ /* If frame has a call object, sync values and clear back-pointer. */
+ if (frame.callobj)
+ ok &= js_PutCallObject(cx, &frame);
+#endif
+#if JS_HAS_ARGS_OBJECT
+ /* If frame has an arguments object, sync values and clear back-pointer. */
+ if (frame.argsobj)
+ ok &= js_PutArgsObject(cx, &frame);
+#endif
+
+ /* Restore cx->fp now that we're done releasing frame objects. */
+ cx->fp = fp;
+
+out2:
+ /* Pop everything we may have allocated off the stack. */
+ JS_ARENA_RELEASE(&cx->stackPool, mark);
+
+ /* Store the return value and restore sp just above it. */
+ *vp = frame.rval;
+ fp->sp = vp + 1;
+
+ /*
+ * Store the location of the JSOP_CALL or JSOP_EVAL that generated the
+ * return value, but only if this is an external (compiled from script
+ * source) call that has stack budget for the generating pc.
+ */
+ if (fp->script && !(flags & JSINVOKE_INTERNAL))
+ vp[-(intN)fp->script->depth] = (jsval)fp->pc;
+ return ok;
+
+bad:
+ js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_CONSTRUCT);
+ ok = JS_FALSE;
+ goto out2;
+}
+
+JSBool
+js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
+ uintN argc, jsval *argv, jsval *rval)
+{
+ JSStackFrame *fp, *oldfp, frame;
+ jsval *oldsp, *sp;
+ void *mark;
+ uintN i;
+ JSBool ok;
+
+ fp = oldfp = cx->fp;
+ if (!fp) {
+ memset(&frame, 0, sizeof frame);
+ cx->fp = fp = &frame;
+ }
+ oldsp = fp->sp;
+ sp = js_AllocStack(cx, 2 + argc, &mark);
+ if (!sp) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ PUSH(fval);
+ PUSH(OBJECT_TO_JSVAL(obj));
+ for (i = 0; i < argc; i++)
+ PUSH(argv[i]);
+ fp->sp = sp;
+ ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL);
+ if (ok) {
+ RESTORE_SP(fp);
+ *rval = POP_OPND();
+ }
+
+ js_FreeStack(cx, mark);
+out:
+ fp->sp = oldsp;
+ if (oldfp != fp)
+ cx->fp = oldfp;
+
+ return ok;
+}
+
+JSBool
+js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
+ JSAccessMode mode, uintN argc, jsval *argv, jsval *rval)
+{
+ /*
+ * Check general (not object-ops/class-specific) access from the running
+ * script to obj.id only if id has a scripted getter or setter that we're
+ * about to invoke. If we don't check this case, nothing else will -- no
+ * other native code has the chance to check.
+ *
+ * Contrast this non-native (scripted) case with native getter and setter
+ * accesses, where the native itself must do an access check, if security
+ * policies requires it. We make a checkAccess or checkObjectAccess call
+ * back to the embedding program only in those cases where we're not going
+ * to call an embedding-defined native function, getter, setter, or class
+ * hook anyway. Where we do call such a native, there's no need for the
+ * engine to impose a separate access check callback on all embeddings --
+ * many embeddings have no security policy at all.
+ */
+ JS_ASSERT(mode == JSACC_READ || mode == JSACC_WRITE);
+ if (cx->runtime->checkObjectAccess &&
+ JSVAL_IS_FUNCTION(cx, fval) &&
+ ((JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval)))->script &&
+ !cx->runtime->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode,
+ &fval)) {
+ return JS_FALSE;
+ }
+
+ return js_InternalCall(cx, obj, fval, argc, argv, rval);
+}
+
+JSBool
+js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
+ JSStackFrame *down, uintN special, jsval *result)
+{
+ JSStackFrame *oldfp, frame;
+ JSObject *obj, *tmp;
+ JSBool ok;
+ JSInterpreterHook hook;
+ void *hookData;
+
+ hook = cx->runtime->executeHook;
+ hookData = NULL;
+ oldfp = cx->fp;
+ frame.callobj = frame.argsobj = NULL;
+ frame.script = script;
+ if (down) {
+ /* Propagate arg/var state for eval and the debugger API. */
+ frame.varobj = down->varobj;
+ frame.fun = down->fun;
+ frame.thisp = down->thisp;
+ frame.argc = down->argc;
+ frame.argv = down->argv;
+ frame.nvars = down->nvars;
+ frame.vars = down->vars;
+ frame.annotation = down->annotation;
+ frame.sharpArray = down->sharpArray;
+ } else {
+ obj = chain;
+ if (cx->options & JSOPTION_VAROBJFIX) {
+ while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
+ obj = tmp;
+ }
+ frame.varobj = obj;
+ frame.fun = NULL;
+ frame.thisp = chain;
+ frame.argc = frame.nvars = 0;
+ frame.argv = frame.vars = NULL;
+ frame.annotation = NULL;
+ frame.sharpArray = NULL;
+ }
+ frame.rval = JSVAL_VOID;
+ frame.down = down;
+ frame.scopeChain = chain;
+ frame.pc = NULL;
+ frame.sp = oldfp ? oldfp->sp : NULL;
+ frame.spbase = NULL;
+ frame.sharpDepth = 0;
+ frame.flags = special;
+ frame.dormantNext = NULL;
+ frame.objAtomMap = NULL;
+
+ /*
+ * Here we wrap the call to js_Interpret with code to (conditionally)
+ * save and restore the old stack frame chain into a chain of 'dormant'
+ * frame chains. Since we are replacing cx->fp, we were running into
+ * the problem that if GC was called under this frame, some of the GC
+ * things associated with the old frame chain (available here only in
+ * the C variable 'oldfp') were not rooted and were being collected.
+ *
+ * So, now we preserve the links to these 'dormant' frame chains in cx
+ * before calling js_Interpret and cleanup afterwards. The GC walks
+ * these dormant chains and marks objects in the same way that it marks
+ * objects in the primary cx->fp chain.
+ */
+ if (oldfp && oldfp != down) {
+ JS_ASSERT(!oldfp->dormantNext);
+ oldfp->dormantNext = cx->dormantFrameChain;
+ cx->dormantFrameChain = oldfp;
+ }
+
+ cx->fp = &frame;
+ if (hook)
+ hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->executeHookData);
+
+ ok = js_Interpret(cx, result);
+
+ if (hookData) {
+ hook = cx->runtime->executeHook;
+ if (hook)
+ hook(cx, &frame, JS_FALSE, &ok, hookData);
+ }
+ cx->fp = oldfp;
+
+ if (oldfp && oldfp != down) {
+ JS_ASSERT(cx->dormantFrameChain == oldfp);
+ cx->dormantFrameChain = oldfp->dormantNext;
+ oldfp->dormantNext = NULL;
+ }
+
+ return ok;
+}
+
+#if JS_HAS_EXPORT_IMPORT
+/*
+ * If id is JSVAL_VOID, import all exported properties from obj.
+ */
+static JSBool
+ImportProperty(JSContext *cx, JSObject *obj, jsid id)
+{
+ JSBool ok;
+ JSIdArray *ida;
+ JSProperty *prop;
+ JSObject *obj2, *target, *funobj, *closure;
+ JSString *str;
+ uintN attrs;
+ jsint i;
+ jsval value;
+
+ if (JSVAL_IS_VOID(id)) {
+ ida = JS_Enumerate(cx, obj);
+ if (!ida)
+ return JS_FALSE;
+ ok = JS_TRUE;
+ if (ida->length == 0)
+ goto out;
+ } else {
+ ida = NULL;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
+ ID_TO_VALUE(id), NULL);
+ if (str)
+ js_ReportIsNotDefined(cx, JS_GetStringBytes(str));
+ return JS_FALSE;
+ }
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ if (!ok)
+ return JS_FALSE;
+ if (!(attrs & JSPROP_EXPORTED)) {
+ str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
+ ID_TO_VALUE(id), NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_NOT_EXPORTED,
+ JS_GetStringBytes(str));
+ }
+ return JS_FALSE;
+ }
+ }
+
+ target = cx->fp->varobj;
+ i = 0;
+ do {
+ if (ida) {
+ id = ida->vector[i];
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, id, NULL, &attrs);
+ if (!ok)
+ goto out;
+ if (!(attrs & JSPROP_EXPORTED))
+ continue;
+ }
+ ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_IMPORT, &value, &attrs);
+ if (!ok)
+ goto out;
+ if (JSVAL_IS_FUNCTION(cx, value)) {
+ funobj = JSVAL_TO_OBJECT(value);
+ closure = js_CloneFunctionObject(cx, funobj, obj);
+ if (!closure) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ value = OBJECT_TO_JSVAL(closure);
+ }
+
+ /*
+ * Handle the case of importing a property that refers to a local
+ * variable or formal parameter of a function activation. These
+ * properties are accessed by opcodes using stack slot numbers
+ * generated by the compiler rather than runtime name-lookup. These
+ * local references, therefore, bypass the normal scope chain lookup.
+ * So, instead of defining a new property in the activation object,
+ * modify the existing value in the stack slot.
+ */
+ if (OBJ_GET_CLASS(cx, target) == &js_CallClass) {
+ ok = OBJ_LOOKUP_PROPERTY(cx, target, id, &obj2, &prop);
+ if (!ok)
+ goto out;
+ } else {
+ prop = NULL;
+ }
+ if (prop && target == obj2) {
+ ok = OBJ_SET_PROPERTY(cx, target, id, &value);
+ } else {
+ ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
+ attrs & ~JSPROP_EXPORTED,
+ NULL);
+ }
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ if (!ok)
+ goto out;
+ } while (ida && ++i < ida->length);
+
+out:
+ if (ida)
+ JS_DestroyIdArray(cx, ida);
+ return ok;
+}
+#endif /* JS_HAS_EXPORT_IMPORT */
+
+JSBool
+js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
+ JSBool *foundp)
+{
+ JSObject *obj2;
+ JSProperty *prop;
+ JSBool ok;
+ uintN oldAttrs, report;
+ JSBool isFunction;
+ jsval value;
+ const char *type, *name;
+
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+ return JS_FALSE;
+ *foundp = (prop != NULL);
+ if (!prop)
+ return JS_TRUE;
+ ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs);
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ if (!ok)
+ return JS_FALSE;
+
+ /* If either property is readonly, we have an error. */
+ report = ((oldAttrs | attrs) & JSPROP_READONLY)
+ ? JSREPORT_ERROR
+ : JSREPORT_WARNING | JSREPORT_STRICT;
+
+ if (report != JSREPORT_ERROR) {
+ /*
+ * Allow redeclaration of variables and functions, but insist that the
+ * new value is not a getter if the old value was, ditto for setters --
+ * unless prop is impermanent (in which case anyone could delete it and
+ * redefine it, willy-nilly).
+ */
+ if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
+ return JS_TRUE;
+ if ((~(oldAttrs ^ attrs) & (JSPROP_GETTER | JSPROP_SETTER)) == 0)
+ return JS_TRUE;
+ if (!(oldAttrs & JSPROP_PERMANENT))
+ return JS_TRUE;
+ report = JSREPORT_ERROR;
+ }
+
+ isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0;
+ if (!isFunction) {
+ if (!OBJ_GET_PROPERTY(cx, obj, id, &value))
+ return JS_FALSE;
+ isFunction = JSVAL_IS_FUNCTION(cx, value);
+ }
+ type = (oldAttrs & attrs & JSPROP_GETTER)
+ ? js_getter_str
+ : (oldAttrs & attrs & JSPROP_SETTER)
+ ? js_setter_str
+ : (oldAttrs & JSPROP_READONLY)
+ ? js_const_str
+ : isFunction
+ ? js_function_str
+ : js_var_str;
+ name = js_AtomToPrintableString(cx, (JSAtom *)id);
+ if (!name)
+ return JS_FALSE;
+ return JS_ReportErrorFlagsAndNumber(cx, report,
+ js_GetErrorMessage, NULL,
+ JSMSG_REDECLARED_VAR,
+ type, name);
+}
+
+#ifndef MAX_INTERP_LEVEL
+#if defined(XP_OS2)
+#define MAX_INTERP_LEVEL 250
+#elif defined _MSC_VER && _MSC_VER <= 800
+#define MAX_INTERP_LEVEL 30
+#else
+#define MAX_INTERP_LEVEL 1000
+#endif
+#endif
+
+#define MAX_INLINE_CALL_COUNT 1000
+
+JSBool
+js_Interpret(JSContext *cx, jsval *result)
+{
+ JSRuntime *rt;
+ JSStackFrame *fp;
+ JSScript *script;
+ uintN inlineCallCount;
+ JSObject *obj, *obj2, *proto, *parent;
+ JSVersion currentVersion, originalVersion;
+ JSBranchCallback onbranch;
+ JSBool ok, cond;
+ JSTrapHandler interruptHandler;
+ jsint depth, len;
+ jsval *sp, *newsp;
+ void *mark;
+ jsbytecode *pc, *pc2, *endpc;
+ JSOp op, op2;
+ const JSCodeSpec *cs;
+ JSAtom *atom;
+ uintN argc, slot, attrs;
+ jsval *vp, lval, rval, ltmp, rtmp;
+ jsid id;
+ JSObject *withobj, *origobj, *propobj;
+ jsval iter_state;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+ JSString *str, *str2;
+ jsint i, j;
+ jsdouble d, d2;
+ JSClass *clasp, *funclasp;
+ JSFunction *fun;
+ JSType type;
+#ifdef DEBUG
+ FILE *tracefp;
+#endif
+#if JS_HAS_EXPORT_IMPORT
+ JSIdArray *ida;
+#endif
+#if JS_HAS_SWITCH_STATEMENT
+ jsint low, high, off, npairs;
+ JSBool match;
+#endif
+#if JS_HAS_GETTER_SETTER
+ JSPropertyOp getter, setter;
+#endif
+ int stackDummy;
+
+ *result = JSVAL_VOID;
+ rt = cx->runtime;
+
+ /* Set registerized frame pointer and derived script pointer. */
+ fp = cx->fp;
+ script = fp->script;
+
+ /* Count of JS function calls that nest in this C js_Interpret frame. */
+ inlineCallCount = 0;
+
+ /*
+ * Optimized Get and SetVersion for proper script language versioning.
+ *
+ * If any native method or JSClass/JSObjectOps hook calls JS_SetVersion
+ * and changes cx->version, the effect will "stick" and we will stop
+ * maintaining currentVersion. This is relied upon by testsuites, for
+ * the most part -- web browsers select version before compiling and not
+ * at run-time.
+ */
+ currentVersion = script->version;
+ originalVersion = cx->version;
+ if (currentVersion != originalVersion)
+ JS_SetVersion(cx, currentVersion);
+
+ /*
+ * Prepare to call a user-supplied branch handler, and abort the script
+ * if it returns false.
+ */
+ onbranch = cx->branchCallback;
+ ok = JS_TRUE;
+#define CHECK_BRANCH(len) \
+ JS_BEGIN_MACRO \
+ if (len <= 0 && onbranch) { \
+ SAVE_SP(fp); \
+ if (!(ok = (*onbranch)(cx, script))) \
+ goto out; \
+ } \
+ JS_END_MACRO
+
+ /*
+ * Load the debugger's interrupt hook here and after calling out to native
+ * functions (but not to getters, setters, or other native hooks), so we do
+ * not have to reload it each time through the interpreter loop -- we hope
+ * the compiler can keep it in a register.
+ * XXX if it spills, we still lose
+ */
+#define LOAD_INTERRUPT_HANDLER(rt) (interruptHandler = (rt)->interruptHandler)
+
+ LOAD_INTERRUPT_HANDLER(rt);
+
+ pc = script->code;
+ endpc = pc + script->length;
+ depth = (jsint) script->depth;
+ len = -1;
+
+ /* Check for too much js_Interpret nesting, or too deep a C stack. */
+ if (++cx->interpLevel == MAX_INTERP_LEVEL ||
+ !JS_CHECK_STACK_SIZE(cx, stackDummy)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ /*
+ * Allocate operand and pc stack slots for the script's worst-case depth.
+ */
+ newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
+ if (!newsp) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ sp = newsp + depth;
+ fp->spbase = sp;
+ SAVE_SP(fp);
+
+ while (pc < endpc) {
+ fp->pc = pc;
+ op = (JSOp) *pc;
+ do_op:
+ cs = &js_CodeSpec[op];
+ len = cs->length;
+
+#ifdef DEBUG
+ tracefp = (FILE *) cx->tracefp;
+ if (tracefp) {
+ intN nuses, n;
+
+ fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, pc));
+ js_Disassemble1(cx, script, pc,
+ PTRDIFF(pc, script->code, jsbytecode), JS_FALSE,
+ tracefp);
+ nuses = cs->nuses;
+ if (nuses) {
+ SAVE_SP(fp);
+ for (n = -nuses; n < 0; n++) {
+ str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
+ if (str != NULL) {
+ fprintf(tracefp, "%s %s",
+ (n == -nuses) ? " inputs:" : ",",
+ JS_GetStringBytes(str));
+ }
+ }
+ fprintf(tracefp, " @ %d\n", sp - fp->spbase);
+ }
+ }
+#endif
+
+ if (interruptHandler) {
+ SAVE_SP(fp);
+ switch (interruptHandler(cx, script, pc, &rval,
+ rt->interruptHandlerData)) {
+ case JSTRAP_ERROR:
+ ok = JS_FALSE;
+ goto out;
+ case JSTRAP_CONTINUE:
+ break;
+ case JSTRAP_RETURN:
+ fp->rval = rval;
+ goto out;
+#if JS_HAS_EXCEPTIONS
+ case JSTRAP_THROW:
+ cx->throwing = JS_TRUE;
+ cx->exception = rval;
+ ok = JS_FALSE;
+ goto out;
+#endif /* JS_HAS_EXCEPTIONS */
+ default:;
+ }
+ LOAD_INTERRUPT_HANDLER(rt);
+ }
+
+ switch (op) {
+ case JSOP_NOP:
+ break;
+
+ case JSOP_GROUP:
+ obj = NULL;
+ break;
+
+ case JSOP_PUSH:
+ PUSH_OPND(JSVAL_VOID);
+ break;
+
+ case JSOP_POP:
+ sp--;
+ break;
+
+ case JSOP_POP2:
+ sp -= 2;
+ break;
+
+ case JSOP_SWAP:
+ /*
+ * N.B. JSOP_SWAP doesn't swap the corresponding generating pcs
+ * for the operands it swaps.
+ */
+ ltmp = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = ltmp;
+ break;
+
+ case JSOP_POPV:
+ *result = POP_OPND();
+ break;
+
+ case JSOP_ENTERWITH:
+ rval = FETCH_OPND(-1);
+ VALUE_TO_OBJECT(cx, rval, obj);
+ withobj = js_NewObject(cx, &js_WithClass, obj, fp->scopeChain);
+ if (!withobj)
+ goto out;
+ fp->scopeChain = withobj;
+ STORE_OPND(-1, OBJECT_TO_JSVAL(withobj));
+ break;
+
+ case JSOP_LEAVEWITH:
+ rval = POP_OPND();
+ JS_ASSERT(JSVAL_IS_OBJECT(rval));
+ withobj = JSVAL_TO_OBJECT(rval);
+ JS_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass);
+
+ rval = OBJ_GET_SLOT(cx, withobj, JSSLOT_PARENT);
+ JS_ASSERT(JSVAL_IS_OBJECT(rval));
+ fp->scopeChain = JSVAL_TO_OBJECT(rval);
+ break;
+
+ case JSOP_SETRVAL:
+ fp->rval = POP_OPND();
+ break;
+
+ case JSOP_RETURN:
+ CHECK_BRANCH(-1);
+ fp->rval = POP_OPND();
+ /* FALL THROUGH */
+
+ case JSOP_RETRVAL: /* fp->rval already set */
+ if (inlineCallCount)
+ inline_return:
+ {
+ JSInlineFrame *ifp = (JSInlineFrame *) fp;
+ void *hookData = ifp->hookData;
+
+ if (hookData) {
+ JSInterpreterHook hook = cx->runtime->callHook;
+ if (hook) {
+ hook(cx, fp, JS_FALSE, &ok, hookData);
+ LOAD_INTERRUPT_HANDLER(rt);
+ }
+ }
+#if JS_HAS_ARGS_OBJECT
+ if (fp->argsobj)
+ ok &= js_PutArgsObject(cx, fp);
+#endif
+
+ /* Restore context version only if callee hasn't set version. */
+ if (cx->version == currentVersion) {
+ currentVersion = ifp->callerVersion;
+ if (currentVersion != cx->version)
+ JS_SetVersion(cx, currentVersion);
+ }
+
+ /* Store the return value in the caller's operand frame. */
+ vp = fp->argv - 2;
+ *vp = fp->rval;
+
+ /* Restore cx->fp and release the inline frame's space. */
+ cx->fp = fp = fp->down;
+ JS_ARENA_RELEASE(&cx->stackPool, ifp->mark);
+
+ /* Restore sp to point just above the return value. */
+ fp->sp = vp + 1;
+ RESTORE_SP(fp);
+
+ /* Restore the calling script's interpreter registers. */
+ script = fp->script;
+ depth = (jsint) script->depth;
+ pc = fp->pc;
+ endpc = script->code + script->length;
+
+ /* Store the generating pc for the return value. */
+ vp[-depth] = (jsval)pc;
+
+ /* Set remaining variables for 'goto advance_pc'. */
+ op = (JSOp) *pc;
+ cs = &js_CodeSpec[op];
+ len = cs->length;
+
+ /* Resume execution in the calling frame. */
+ inlineCallCount--;
+ if (ok)
+ goto advance_pc;
+ }
+ goto out;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case JSOP_DEFAULT:
+ (void) POP();
+ /* FALL THROUGH */
+#endif
+ case JSOP_GOTO:
+ len = GET_JUMP_OFFSET(pc);
+ CHECK_BRANCH(len);
+ break;
+
+ case JSOP_IFEQ:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond == JS_FALSE) {
+ len = GET_JUMP_OFFSET(pc);
+ CHECK_BRANCH(len);
+ }
+ break;
+
+ case JSOP_IFNE:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond != JS_FALSE) {
+ len = GET_JUMP_OFFSET(pc);
+ CHECK_BRANCH(len);
+ }
+ break;
+
+ case JSOP_OR:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond == JS_TRUE) {
+ len = GET_JUMP_OFFSET(pc);
+ PUSH_OPND(rval);
+ }
+ break;
+
+ case JSOP_AND:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond == JS_FALSE) {
+ len = GET_JUMP_OFFSET(pc);
+ PUSH_OPND(rval);
+ }
+ break;
+
+
+#if JS_HAS_SWITCH_STATEMENT
+ case JSOP_DEFAULTX:
+ (void) POP();
+ /* FALL THROUGH */
+#endif
+ case JSOP_GOTOX:
+ len = GET_JUMPX_OFFSET(pc);
+ CHECK_BRANCH(len);
+ break;
+
+ case JSOP_IFEQX:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond == JS_FALSE) {
+ len = GET_JUMPX_OFFSET(pc);
+ CHECK_BRANCH(len);
+ }
+ break;
+
+ case JSOP_IFNEX:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond != JS_FALSE) {
+ len = GET_JUMPX_OFFSET(pc);
+ CHECK_BRANCH(len);
+ }
+ break;
+
+ case JSOP_ORX:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond == JS_TRUE) {
+ len = GET_JUMPX_OFFSET(pc);
+ PUSH_OPND(rval);
+ }
+ break;
+
+ case JSOP_ANDX:
+ POP_BOOLEAN(cx, rval, cond);
+ if (cond == JS_FALSE) {
+ len = GET_JUMPX_OFFSET(pc);
+ PUSH_OPND(rval);
+ }
+ break;
+
+ case JSOP_TOOBJECT:
+ SAVE_SP(fp);
+ ok = js_ValueToObject(cx, FETCH_OPND(-1), &obj);
+ if (!ok)
+ goto out;
+ STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
+ break;
+
+#define FETCH_ELEMENT_ID(n, id) \
+ JS_BEGIN_MACRO \
+ /* If the index is not a jsint, atomize it. */ \
+ id = (jsid) FETCH_OPND(n); \
+ if (JSVAL_IS_INT(id)) { \
+ atom = NULL; \
+ } else { \
+ SAVE_SP(fp); \
+ atom = js_ValueToStringAtom(cx, (jsval)id); \
+ if (!atom) { \
+ ok = JS_FALSE; \
+ goto out; \
+ } \
+ id = (jsid)atom; \
+ } \
+ JS_END_MACRO
+
+#define POP_ELEMENT_ID(id) \
+ JS_BEGIN_MACRO \
+ FETCH_ELEMENT_ID(-1, id); \
+ sp--; \
+ JS_END_MACRO
+
+#if JS_HAS_IN_OPERATOR
+ case JSOP_IN:
+ rval = FETCH_OPND(-1);
+ if (JSVAL_IS_PRIMITIVE(rval)) {
+ str = js_DecompileValueGenerator(cx, -1, rval, NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_IN_NOT_OBJECT,
+ JS_GetStringBytes(str));
+ }
+ ok = JS_FALSE;
+ goto out;
+ }
+ sp--;
+ obj = JSVAL_TO_OBJECT(rval);
+ FETCH_ELEMENT_ID(-1, id);
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
+ if (!ok)
+ goto out;
+ STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop != NULL));
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ break;
+#endif /* JS_HAS_IN_OPERATOR */
+
+ case JSOP_FORPROP:
+ /*
+ * Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
+ * is not paid for the more common cases.
+ */
+ lval = FETCH_OPND(-1);
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ i = -2;
+ goto do_forinloop;
+
+ case JSOP_FORNAME:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+
+ /*
+ * ECMA 12.6.3 says to eval the LHS after looking for properties
+ * to enumerate, and bail without LHS eval if there are no props.
+ * We do Find here to share the most code at label do_forinloop.
+ * If looking for enumerable properties could have side effects,
+ * then we'd have to move this into the common code and condition
+ * it on op == JSOP_FORNAME.
+ */
+ SAVE_SP(fp);
+ ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
+ if (!ok)
+ goto out;
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ lval = OBJECT_TO_JSVAL(obj);
+ /* FALL THROUGH */
+
+ case JSOP_FORARG:
+ case JSOP_FORVAR:
+ /*
+ * JSOP_FORARG and JSOP_FORVAR don't require any lval computation
+ * here, because they address slots on the stack (in fp->args and
+ * fp->vars, respectively).
+ */
+ /* FALL THROUGH */
+
+ case JSOP_FORELEM:
+ /*
+ * JSOP_FORELEM simply initializes or updates the iteration state
+ * and leaves the index expression evaluation and assignment to the
+ * enumerator until after the next property has been acquired, via
+ * a JSOP_ENUMELEM bytecode.
+ */
+ i = -1;
+
+ do_forinloop:
+ /*
+ * ECMA-compatible for/in evals the object just once, before loop.
+ * Bad old bytecodes (since removed) did it on every iteration.
+ */
+ obj = JSVAL_TO_OBJECT(sp[i]);
+
+ /* If the thing to the right of 'in' has no properties, break. */
+ if (!obj) {
+ rval = JSVAL_FALSE;
+ goto end_forinloop;
+ }
+
+ /*
+ * Save the thing to the right of 'in' as origobj. Later on, we
+ * use this variable to suppress enumeration of shadowed prototype
+ * properties.
+ */
+ origobj = obj;
+
+ /*
+ * Reach under the top of stack to find our property iterator, a
+ * JSObject that contains the iteration state. (An object is used
+ * rather than a native struct so that the iteration state is
+ * cleaned up via GC if the for-in loop terminates abruptly.)
+ */
+ vp = &sp[i - 1];
+ rval = *vp;
+
+ /* Is this the first iteration ? */
+ if (JSVAL_IS_VOID(rval)) {
+ /* Yes, create a new JSObject to hold the iterator state */
+ propobj = js_NewObject(cx, &prop_iterator_class, NULL, obj);
+ if (!propobj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ propobj->slots[JSSLOT_ITER_STATE] = JSVAL_NULL;
+
+ /*
+ * Root the parent slot so we can get it even in our finalizer
+ * (otherwise, it would live as long as we do, but it might be
+ * finalized first).
+ */
+ ok = js_AddRoot(cx, &propobj->slots[JSSLOT_PARENT],
+ "propobj->parent");
+ if (!ok)
+ goto out;
+
+ /*
+ * Rewrite the iterator so we know to do the next case.
+ * Do this before calling the enumerator, which could
+ * displace cx->newborn and cause GC.
+ */
+ *vp = OBJECT_TO_JSVAL(propobj);
+
+ ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);
+
+ /*
+ * Stash private iteration state into property iterator object.
+ * We do this before checking 'ok' to ensure that propobj is
+ * in a valid state even if OBJ_ENUMERATE returned JS_FALSE.
+ * NB: This code knows that the first slots are pre-allocated.
+ */
+#if JS_INITIAL_NSLOTS < 5
+#error JS_INITIAL_NSLOTS must be greater than or equal to 5.
+#endif
+ propobj->slots[JSSLOT_ITER_STATE] = iter_state;
+ if (!ok)
+ goto out;
+ } else {
+ /* This is not the first iteration. Recover iterator state. */
+ propobj = JSVAL_TO_OBJECT(rval);
+ obj = JSVAL_TO_OBJECT(propobj->slots[JSSLOT_PARENT]);
+ iter_state = propobj->slots[JSSLOT_ITER_STATE];
+ }
+
+ enum_next_property:
+ /* Get the next jsid to be enumerated and store it in rval. */
+ OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &rval);
+ propobj->slots[JSSLOT_ITER_STATE] = iter_state;
+
+ /* No more jsids to iterate in obj? */
+ if (iter_state == JSVAL_NULL) {
+ /* Enumerate the properties on obj's prototype chain. */
+ obj = OBJ_GET_PROTO(cx, obj);
+ if (!obj) {
+ /* End of property list -- terminate loop. */
+ rval = JSVAL_FALSE;
+ goto end_forinloop;
+ }
+
+ ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);
+
+ /*
+ * Stash private iteration state into property iterator object.
+ * We do this before checking 'ok' to ensure that propobj is
+ * in a valid state even if OBJ_ENUMERATE returned JS_FALSE.
+ * NB: This code knows that the first slots are pre-allocated.
+ */
+ propobj->slots[JSSLOT_ITER_STATE] = iter_state;
+ if (!ok)
+ goto out;
+
+ /*
+ * Update the iterator JSObject's parent link to refer to the
+ * current object. This is used in the iterator JSObject's
+ * finalizer.
+ */
+ propobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj);
+ goto enum_next_property;
+ }
+
+ /* Skip properties not owned by obj, and leave next id in rval. */
+ ok = OBJ_LOOKUP_PROPERTY(cx, origobj, rval, &obj2, &prop);
+ if (!ok)
+ goto out;
+ if (prop) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+
+ /* Yes, don't enumerate again. Go to the next property. */
+ if (obj2 != obj)
+ goto enum_next_property;
+ }
+
+ /* Make sure rval is a string for uniformity and compatibility. */
+ if (!JSVAL_IS_INT(rval)) {
+ rval = ATOM_KEY((JSAtom *)rval);
+ } else if (cx->version != JSVERSION_1_2) {
+ str = js_NumberToString(cx, (jsdouble) JSVAL_TO_INT(rval));
+ if (!str) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ rval = STRING_TO_JSVAL(str);
+ }
+
+ switch (op) {
+ case JSOP_FORARG:
+ slot = GET_ARGNO(pc);
+ JS_ASSERT(slot < fp->fun->nargs);
+ fp->argv[slot] = rval;
+ break;
+
+ case JSOP_FORVAR:
+ slot = GET_VARNO(pc);
+ JS_ASSERT(slot < fp->fun->nvars);
+ fp->vars[slot] = rval;
+ break;
+
+ case JSOP_FORELEM:
+ /* FORELEM is not a SET operation, it's more like BINDNAME. */
+ PUSH_OPND(rval);
+ break;
+
+ default:
+ /* Convert lval to a non-null object containing id. */
+ VALUE_TO_OBJECT(cx, lval, obj);
+
+ /* Set the variable obj[id] to refer to rval. */
+ fp->flags |= JSFRAME_ASSIGNING;
+ ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
+ fp->flags &= ~JSFRAME_ASSIGNING;
+ if (!ok)
+ goto out;
+ break;
+ }
+
+ /* Push true to keep looping through properties. */
+ rval = JSVAL_TRUE;
+
+ end_forinloop:
+ sp += i + 1;
+ PUSH_OPND(rval);
+ break;
+
+ case JSOP_DUP:
+ JS_ASSERT(sp > fp->spbase);
+ rval = sp[-1];
+ PUSH_OPND(rval);
+ break;
+
+ case JSOP_DUP2:
+ JS_ASSERT(sp - 1 > fp->spbase);
+ lval = FETCH_OPND(-2);
+ rval = FETCH_OPND(-1);
+ PUSH_OPND(lval);
+ PUSH_OPND(rval);
+ break;
+
+#define PROPERTY_OP(n, call) \
+ JS_BEGIN_MACRO \
+ /* Pop the left part and resolve it to a non-null object. */ \
+ lval = FETCH_OPND(n); \
+ VALUE_TO_OBJECT(cx, lval, obj); \
+ \
+ /* Get or set the property, set ok false if error, true if success. */\
+ SAVE_SP(fp); \
+ call; \
+ if (!ok) \
+ goto out; \
+ JS_END_MACRO
+
+#define ELEMENT_OP(n, call) \
+ JS_BEGIN_MACRO \
+ FETCH_ELEMENT_ID(n, id); \
+ PROPERTY_OP(n-1, call); \
+ JS_END_MACRO
+
+/*
+ * Direct callers, i.e. those who do not wrap CACHED_GET and CACHED_SET calls
+ * in PROPERTY_OP or ELEMENT_OP macro calls must SAVE_SP(fp); beforehand, just
+ * in case a getter or setter function is invoked.
+ */
+#define CACHED_GET(call) \
+ JS_BEGIN_MACRO \
+ if (!OBJ_IS_NATIVE(obj)) { \
+ ok = call; \
+ } else { \
+ JS_LOCK_OBJ(cx, obj); \
+ PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop); \
+ if (sprop) { \
+ JSScope *scope_ = OBJ_SCOPE(obj); \
+ slot = (uintN)sprop->slot; \
+ rval = (slot != SPROP_INVALID_SLOT) \
+ ? LOCKED_OBJ_GET_SLOT(obj, slot) \
+ : JSVAL_VOID; \
+ JS_UNLOCK_SCOPE(cx, scope_); \
+ ok = SPROP_GET(cx, sprop, obj, obj, &rval); \
+ JS_LOCK_SCOPE(cx, scope_); \
+ if (ok && SPROP_HAS_VALID_SLOT(sprop, scope_)) \
+ LOCKED_OBJ_SET_SLOT(obj, slot, rval); \
+ JS_UNLOCK_SCOPE(cx, scope_); \
+ } else { \
+ JS_UNLOCK_OBJ(cx, obj); \
+ ok = call; \
+ /* No fill here: js_GetProperty fills the cache. */ \
+ } \
+ } \
+ JS_END_MACRO
+
+#define CACHED_SET(call) \
+ JS_BEGIN_MACRO \
+ if (!OBJ_IS_NATIVE(obj)) { \
+ ok = call; \
+ } else { \
+ JSScope *scope_; \
+ JS_LOCK_OBJ(cx, obj); \
+ PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop); \
+ if (sprop && \
+ !(sprop->attrs & JSPROP_READONLY) && \
+ (scope_ = OBJ_SCOPE(obj), !SCOPE_IS_SEALED(scope_))) { \
+ JS_UNLOCK_SCOPE(cx, scope_); \
+ ok = SPROP_SET(cx, sprop, obj, obj, &rval); \
+ JS_LOCK_SCOPE(cx, scope_); \
+ if (ok && SPROP_HAS_VALID_SLOT(sprop, scope_)) { \
+ LOCKED_OBJ_SET_SLOT(obj, sprop->slot, rval); \
+ GC_POKE(cx, JSVAL_NULL); /* XXX second arg ignored */ \
+ } \
+ JS_UNLOCK_SCOPE(cx, scope_); \
+ } else { \
+ JS_UNLOCK_OBJ(cx, obj); \
+ ok = call; \
+ /* No fill here: js_SetProperty writes through the cache. */ \
+ } \
+ } \
+ JS_END_MACRO
+
+ case JSOP_SETCONST:
+ obj = fp->varobj;
+ atom = GET_ATOM(cx, script, pc);
+ rval = FETCH_OPND(-1);
+ ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, rval, NULL, NULL,
+ JSPROP_ENUMERATE | JSPROP_PERMANENT |
+ JSPROP_READONLY,
+ NULL);
+ if (!ok)
+ goto out;
+ STORE_OPND(-1, rval);
+ break;
+
+ case JSOP_BINDNAME:
+ atom = GET_ATOM(cx, script, pc);
+ SAVE_SP(fp);
+ obj = js_FindIdentifierBase(cx, (jsid)atom);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ PUSH_OPND(OBJECT_TO_JSVAL(obj));
+ break;
+
+ case JSOP_SETNAME:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ rval = FETCH_OPND(-1);
+ lval = FETCH_OPND(-2);
+ JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
+ obj = JSVAL_TO_OBJECT(lval);
+ SAVE_SP(fp);
+ CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
+ if (!ok)
+ goto out;
+ sp--;
+ STORE_OPND(-1, rval);
+ break;
+
+#define INTEGER_OP(OP, EXTRA_CODE) \
+ JS_BEGIN_MACRO \
+ FETCH_INT(cx, -1, j); \
+ FETCH_INT(cx, -2, i); \
+ if (!ok) \
+ goto out; \
+ EXTRA_CODE \
+ d = i OP j; \
+ sp--; \
+ STORE_NUMBER(cx, -1, d); \
+ JS_END_MACRO
+
+#define BITWISE_OP(OP) INTEGER_OP(OP, (void) 0;)
+#define SIGNED_SHIFT_OP(OP) INTEGER_OP(OP, j &= 31;)
+
+ case JSOP_BITOR:
+ BITWISE_OP(|);
+ break;
+
+ case JSOP_BITXOR:
+ BITWISE_OP(^);
+ break;
+
+ case JSOP_BITAND:
+ BITWISE_OP(&);
+ break;
+
+#if defined(XP_WIN)
+#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) \
+ ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL)) \
+ ? (IFNAN) \
+ : (LVAL) OP (RVAL))
+#else
+#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))
+#endif
+
+#define RELATIONAL_OP(OP) \
+ JS_BEGIN_MACRO \
+ rval = FETCH_OPND(-1); \
+ lval = FETCH_OPND(-2); \
+ /* Optimize for two int-tagged operands (typical loop control). */ \
+ if ((lval & rval) & JSVAL_INT) { \
+ ltmp = lval ^ JSVAL_VOID; \
+ rtmp = rval ^ JSVAL_VOID; \
+ if (ltmp && rtmp) { \
+ cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \
+ } else { \
+ d = ltmp ? JSVAL_TO_INT(lval) : *rt->jsNaN; \
+ d2 = rtmp ? JSVAL_TO_INT(rval) : *rt->jsNaN; \
+ cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE); \
+ } \
+ } else { \
+ VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_NUMBER, &lval); \
+ VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_NUMBER, &rval); \
+ if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \
+ str = JSVAL_TO_STRING(lval); \
+ str2 = JSVAL_TO_STRING(rval); \
+ cond = js_CompareStrings(str, str2) OP 0; \
+ } else { \
+ VALUE_TO_NUMBER(cx, lval, d); \
+ VALUE_TO_NUMBER(cx, rval, d2); \
+ cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE); \
+ } \
+ } \
+ sp--; \
+ STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
+ JS_END_MACRO
+
+#define EQUALITY_OP(OP, IFNAN) \
+ JS_BEGIN_MACRO \
+ rval = FETCH_OPND(-1); \
+ lval = FETCH_OPND(-2); \
+ ltmp = JSVAL_TAG(lval); \
+ rtmp = JSVAL_TAG(rval); \
+ if (ltmp == rtmp) { \
+ if (ltmp == JSVAL_STRING) { \
+ str = JSVAL_TO_STRING(lval); \
+ str2 = JSVAL_TO_STRING(rval); \
+ cond = js_CompareStrings(str, str2) OP 0; \
+ } else if (ltmp == JSVAL_DOUBLE) { \
+ d = *JSVAL_TO_DOUBLE(lval); \
+ d2 = *JSVAL_TO_DOUBLE(rval); \
+ cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
+ } else { \
+ /* Handle all undefined (=>NaN) and int combinations. */ \
+ cond = lval OP rval; \
+ } \
+ } else { \
+ if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \
+ cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \
+ } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \
+ cond = 1 OP 0; \
+ } else { \
+ if (ltmp == JSVAL_OBJECT) { \
+ VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &lval); \
+ ltmp = JSVAL_TAG(lval); \
+ } else if (rtmp == JSVAL_OBJECT) { \
+ VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &rval); \
+ rtmp = JSVAL_TAG(rval); \
+ } \
+ if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \
+ str = JSVAL_TO_STRING(lval); \
+ str2 = JSVAL_TO_STRING(rval); \
+ cond = js_CompareStrings(str, str2) OP 0; \
+ } else { \
+ VALUE_TO_NUMBER(cx, lval, d); \
+ VALUE_TO_NUMBER(cx, rval, d2); \
+ cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
+ } \
+ } \
+ } \
+ sp--; \
+ STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
+ JS_END_MACRO
+
+ case JSOP_EQ:
+ EQUALITY_OP(==, JS_FALSE);
+ break;
+
+ case JSOP_NE:
+ EQUALITY_OP(!=, JS_TRUE);
+ break;
+
+#if !JS_BUG_FALLIBLE_EQOPS
+#define NEW_EQUALITY_OP(OP, IFNAN) \
+ JS_BEGIN_MACRO \
+ rval = FETCH_OPND(-1); \
+ lval = FETCH_OPND(-2); \
+ ltmp = JSVAL_TAG(lval); \
+ rtmp = JSVAL_TAG(rval); \
+ if (ltmp == rtmp) { \
+ if (ltmp == JSVAL_STRING) { \
+ str = JSVAL_TO_STRING(lval); \
+ str2 = JSVAL_TO_STRING(rval); \
+ cond = js_CompareStrings(str, str2) OP 0; \
+ } else if (ltmp == JSVAL_DOUBLE) { \
+ d = *JSVAL_TO_DOUBLE(lval); \
+ d2 = *JSVAL_TO_DOUBLE(rval); \
+ cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
+ } else { \
+ cond = lval OP rval; \
+ } \
+ } else { \
+ if (ltmp == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) { \
+ d = *JSVAL_TO_DOUBLE(lval); \
+ d2 = JSVAL_TO_INT(rval); \
+ cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
+ } else if (JSVAL_IS_INT(lval) && rtmp == JSVAL_DOUBLE) { \
+ d = JSVAL_TO_INT(lval); \
+ d2 = *JSVAL_TO_DOUBLE(rval); \
+ cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
+ } else { \
+ cond = lval OP rval; \
+ } \
+ } \
+ sp--; \
+ STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
+ JS_END_MACRO
+
+ case JSOP_NEW_EQ:
+ NEW_EQUALITY_OP(==, JS_FALSE);
+ break;
+
+ case JSOP_NEW_NE:
+ NEW_EQUALITY_OP(!=, JS_TRUE);
+ break;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case JSOP_CASE:
+ NEW_EQUALITY_OP(==, JS_FALSE);
+ (void) POP();
+ if (cond) {
+ len = GET_JUMP_OFFSET(pc);
+ CHECK_BRANCH(len);
+ } else {
+ PUSH(lval);
+ }
+ break;
+
+ case JSOP_CASEX:
+ NEW_EQUALITY_OP(==, JS_FALSE);
+ (void) POP();
+ if (cond) {
+ len = GET_JUMPX_OFFSET(pc);
+ CHECK_BRANCH(len);
+ } else {
+ PUSH(lval);
+ }
+ break;
+#endif
+
+#endif /* !JS_BUG_FALLIBLE_EQOPS */
+
+ case JSOP_LT:
+ RELATIONAL_OP(<);
+ break;
+
+ case JSOP_LE:
+ RELATIONAL_OP(<=);
+ break;
+
+ case JSOP_GT:
+ RELATIONAL_OP(>);
+ break;
+
+ case JSOP_GE:
+ RELATIONAL_OP(>=);
+ break;
+
+#undef EQUALITY_OP
+#undef RELATIONAL_OP
+
+ case JSOP_LSH:
+ SIGNED_SHIFT_OP(<<);
+ break;
+
+ case JSOP_RSH:
+ SIGNED_SHIFT_OP(>>);
+ break;
+
+ case JSOP_URSH:
+ {
+ uint32 u;
+
+ FETCH_INT(cx, -1, j);
+ FETCH_UINT(cx, -2, u);
+ j &= 31;
+ d = u >> j;
+ sp--;
+ STORE_NUMBER(cx, -1, d);
+ break;
+ }
+
+#undef INTEGER_OP
+#undef BITWISE_OP
+#undef SIGNED_SHIFT_OP
+
+ case JSOP_ADD:
+ rval = FETCH_OPND(-1);
+ lval = FETCH_OPND(-2);
+ VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &ltmp);
+ VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &rtmp);
+ if ((cond = JSVAL_IS_STRING(ltmp)) || JSVAL_IS_STRING(rtmp)) {
+ if (cond) {
+ str = JSVAL_TO_STRING(ltmp);
+ SAVE_SP(fp);
+ ok = (str2 = js_ValueToString(cx, rtmp)) != NULL;
+ } else {
+ str2 = JSVAL_TO_STRING(rtmp);
+ SAVE_SP(fp);
+ ok = (str = js_ValueToString(cx, ltmp)) != NULL;
+ }
+ if (!ok)
+ goto out;
+ str = js_ConcatStrings(cx, str, str2);
+ if (!str) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ sp--;
+ STORE_OPND(-1, STRING_TO_JSVAL(str));
+ } else {
+ VALUE_TO_NUMBER(cx, lval, d);
+ VALUE_TO_NUMBER(cx, rval, d2);
+ d += d2;
+ sp--;
+ STORE_NUMBER(cx, -1, d);
+ }
+ break;
+
+#define BINARY_OP(OP) \
+ JS_BEGIN_MACRO \
+ FETCH_NUMBER(cx, -1, d2); \
+ FETCH_NUMBER(cx, -2, d); \
+ d = d OP d2; \
+ sp--; \
+ STORE_NUMBER(cx, -1, d); \
+ JS_END_MACRO
+
+ case JSOP_SUB:
+ BINARY_OP(-);
+ break;
+
+ case JSOP_MUL:
+ BINARY_OP(*);
+ break;
+
+ case JSOP_DIV:
+ FETCH_NUMBER(cx, -1, d2);
+ FETCH_NUMBER(cx, -2, d);
+ sp--;
+ if (d2 == 0) {
+#if defined(XP_WIN)
+ /* XXX MSVC miscompiles such that (NaN == 0) */
+ if (JSDOUBLE_IS_NaN(d2))
+ rval = DOUBLE_TO_JSVAL(rt->jsNaN);
+ else
+#endif
+ if (d == 0 || JSDOUBLE_IS_NaN(d))
+ rval = DOUBLE_TO_JSVAL(rt->jsNaN);
+ else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31)
+ rval = DOUBLE_TO_JSVAL(rt->jsNegativeInfinity);
+ else
+ rval = DOUBLE_TO_JSVAL(rt->jsPositiveInfinity);
+ STORE_OPND(-1, rval);
+ } else {
+ d /= d2;
+ STORE_NUMBER(cx, -1, d);
+ }
+ break;
+
+ case JSOP_MOD:
+ FETCH_NUMBER(cx, -1, d2);
+ FETCH_NUMBER(cx, -2, d);
+ sp--;
+ if (d2 == 0) {
+ STORE_OPND(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
+ } else {
+#if defined(XP_WIN)
+ /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
+ if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
+#endif
+ d = fmod(d, d2);
+ STORE_NUMBER(cx, -1, d);
+ }
+ break;
+
+ case JSOP_NOT:
+ POP_BOOLEAN(cx, rval, cond);
+ PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
+ break;
+
+ case JSOP_BITNOT:
+ FETCH_INT(cx, -1, i);
+ d = (jsdouble) ~i;
+ STORE_NUMBER(cx, -1, d);
+ break;
+
+ case JSOP_NEG:
+ FETCH_NUMBER(cx, -1, d);
+#ifdef HPUX
+ /*
+ * Negation of a zero doesn't produce a negative
+ * zero on HPUX. Perform the operation by bit
+ * twiddling.
+ */
+ JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT;
+#else
+ d = -d;
+#endif
+ STORE_NUMBER(cx, -1, d);
+ break;
+
+ case JSOP_POS:
+ FETCH_NUMBER(cx, -1, d);
+ STORE_NUMBER(cx, -1, d);
+ break;
+
+ case JSOP_NEW:
+ /* Get immediate argc and find the constructor function. */
+ argc = GET_ARGC(pc);
+
+#if JS_HAS_INITIALIZERS
+ do_new:
+#endif
+ vp = sp - (2 + argc);
+ JS_ASSERT(vp >= fp->spbase);
+
+ fun = NULL;
+ obj2 = NULL;
+ lval = *vp;
+ if (!JSVAL_IS_OBJECT(lval) ||
+ (obj2 = JSVAL_TO_OBJECT(lval)) == NULL ||
+ /* XXX clean up to avoid special cases above ObjectOps layer */
+ OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass ||
+ !obj2->map->ops->construct)
+ {
+ SAVE_SP(fp);
+ fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT);
+ if (!fun) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+
+ clasp = &js_ObjectClass;
+ if (!obj2) {
+ proto = parent = NULL;
+ fun = NULL;
+ } else {
+ /* Get the constructor prototype object for this function. */
+ ok = OBJ_GET_PROPERTY(cx, obj2,
+ (jsid)rt->atomState.classPrototypeAtom,
+ &rval);
+ if (!ok)
+ goto out;
+ proto = JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL;
+ parent = OBJ_GET_PARENT(cx, obj2);
+
+ if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) {
+ funclasp = ((JSFunction *)JS_GetPrivate(cx, obj2))->clasp;
+ if (funclasp)
+ clasp = funclasp;
+ }
+ }
+ obj = js_NewObject(cx, clasp, proto, parent);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ /* Now we have an object with a constructor method; call it. */
+ vp[1] = OBJECT_TO_JSVAL(obj);
+ SAVE_SP(fp);
+ ok = js_Invoke(cx, argc, JSINVOKE_CONSTRUCT);
+ RESTORE_SP(fp);
+ LOAD_INTERRUPT_HANDLER(rt);
+ if (!ok) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ goto out;
+ }
+
+ /* Check the return value and update obj from it. */
+ rval = *vp;
+ if (JSVAL_IS_PRIMITIVE(rval)) {
+ if (fun || !JSVERSION_IS_ECMA(cx->version)) {
+ *vp = OBJECT_TO_JSVAL(obj);
+ break;
+ }
+ /* native [[Construct]] returning primitive is error */
+ str = js_ValueToString(cx, rval);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_NEW_RESULT,
+ JS_GetStringBytes(str));
+ }
+ ok = JS_FALSE;
+ goto out;
+ }
+ obj = JSVAL_TO_OBJECT(rval);
+ JS_RUNTIME_METER(rt, constructs);
+ break;
+
+ case JSOP_DELNAME:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+
+ SAVE_SP(fp);
+ ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
+ if (!ok)
+ goto out;
+
+ /* ECMA says to return true if name is undefined or inherited. */
+ rval = JSVAL_TRUE;
+ if (prop) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval);
+ if (!ok)
+ goto out;
+ }
+ PUSH_OPND(rval);
+ break;
+
+ case JSOP_DELPROP:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ PROPERTY_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
+ STORE_OPND(-1, rval);
+ break;
+
+ case JSOP_DELELEM:
+ ELEMENT_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
+ sp--;
+ STORE_OPND(-1, rval);
+ break;
+
+ case JSOP_TYPEOF:
+ rval = POP_OPND();
+ type = JS_TypeOfValue(cx, rval);
+ atom = rt->atomState.typeAtoms[type];
+ str = ATOM_TO_STRING(atom);
+ PUSH_OPND(STRING_TO_JSVAL(str));
+ break;
+
+ case JSOP_VOID:
+ (void) POP_OPND();
+ PUSH_OPND(JSVAL_VOID);
+ break;
+
+ case JSOP_INCNAME:
+ case JSOP_DECNAME:
+ case JSOP_NAMEINC:
+ case JSOP_NAMEDEC:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+
+ SAVE_SP(fp);
+ ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
+ if (!ok)
+ goto out;
+ if (!prop)
+ goto atom_not_defined;
+
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ lval = OBJECT_TO_JSVAL(obj);
+ goto do_incop;
+
+ case JSOP_INCPROP:
+ case JSOP_DECPROP:
+ case JSOP_PROPINC:
+ case JSOP_PROPDEC:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ lval = POP_OPND();
+ goto do_incop;
+
+ case JSOP_INCELEM:
+ case JSOP_DECELEM:
+ case JSOP_ELEMINC:
+ case JSOP_ELEMDEC:
+ POP_ELEMENT_ID(id);
+ lval = POP_OPND();
+
+ do_incop:
+ VALUE_TO_OBJECT(cx, lval, obj);
+
+ /* The operand must contain a number. */
+ SAVE_SP(fp);
+ CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
+ if (!ok)
+ goto out;
+
+ /* The expression result goes in rtmp, the updated value in rval. */
+ if (JSVAL_IS_INT(rval) &&
+ rval != INT_TO_JSVAL(JSVAL_INT_MIN) &&
+ rval != INT_TO_JSVAL(JSVAL_INT_MAX)) {
+ if (cs->format & JOF_POST) {
+ rtmp = rval;
+ (cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
+ } else {
+ (cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
+ rtmp = rval;
+ }
+ } else {
+
+/*
+ * Initially, rval contains the value to increment or decrement, which is not
+ * yet converted. As above, the expression result goes in rtmp, the updated
+ * value goes in rval.
+ */
+#define NONINT_INCREMENT_OP() \
+ JS_BEGIN_MACRO \
+ VALUE_TO_NUMBER(cx, rval, d); \
+ if (cs->format & JOF_POST) { \
+ rtmp = rval; \
+ if (!JSVAL_IS_NUMBER(rtmp)) { \
+ ok = js_NewNumberValue(cx, d, &rtmp); \
+ if (!ok) \
+ goto out; \
+ } \
+ (cs->format & JOF_INC) ? d++ : d--; \
+ ok = js_NewNumberValue(cx, d, &rval); \
+ } else { \
+ (cs->format & JOF_INC) ? ++d : --d; \
+ ok = js_NewNumberValue(cx, d, &rval); \
+ rtmp = rval; \
+ } \
+ if (!ok) \
+ goto out; \
+ JS_END_MACRO
+
+ NONINT_INCREMENT_OP();
+ }
+
+ CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
+ if (!ok)
+ goto out;
+ PUSH_OPND(rtmp);
+ break;
+
+/*
+ * NB: This macro can't use JS_BEGIN_MACRO/JS_END_MACRO around its body because
+ * it must break from the switch case that calls it, not from the do...while(0)
+ * loop created by the JS_BEGIN/END_MACRO brackets.
+ */
+#define FAST_INCREMENT_OP(SLOT,COUNT,BASE,PRE,OP,MINMAX) \
+ slot = (uintN)SLOT; \
+ JS_ASSERT(slot < fp->fun->COUNT); \
+ vp = fp->BASE + slot; \
+ rval = *vp; \
+ if (JSVAL_IS_INT(rval) && \
+ rval != INT_TO_JSVAL(JSVAL_INT_##MINMAX)) { \
+ PRE = rval; \
+ rval OP 2; \
+ *vp = rval; \
+ PUSH_OPND(PRE); \
+ break; \
+ } \
+ goto do_nonint_fast_incop;
+
+ case JSOP_INCARG:
+ FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, +=, MAX);
+ case JSOP_DECARG:
+ FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, -=, MIN);
+ case JSOP_ARGINC:
+ FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, +=, MAX);
+ case JSOP_ARGDEC:
+ FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, -=, MIN);
+
+ case JSOP_INCVAR:
+ FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rval, +=, MAX);
+ case JSOP_DECVAR:
+ FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rval, -=, MIN);
+ case JSOP_VARINC:
+ FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rtmp, +=, MAX);
+ case JSOP_VARDEC:
+ FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rtmp, -=, MIN);
+
+#undef FAST_INCREMENT_OP
+
+ do_nonint_fast_incop:
+ NONINT_INCREMENT_OP();
+ *vp = rval;
+ PUSH_OPND(rtmp);
+ break;
+
+ case JSOP_GETPROP:
+ /* Get an immediate atom naming the property. */
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ PROPERTY_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)));
+ STORE_OPND(-1, rval);
+ break;
+
+ case JSOP_SETPROP:
+ /* Pop the right-hand side into rval for OBJ_SET_PROPERTY. */
+ rval = FETCH_OPND(-1);
+
+ /* Get an immediate atom naming the property. */
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ PROPERTY_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
+ sp--;
+ STORE_OPND(-1, rval);
+ break;
+
+ case JSOP_GETELEM:
+ ELEMENT_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)));
+ sp--;
+ STORE_OPND(-1, rval);
+ break;
+
+ case JSOP_SETELEM:
+ rval = FETCH_OPND(-1);
+ ELEMENT_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
+ sp -= 2;
+ STORE_OPND(-1, rval);
+ break;
+
+ case JSOP_ENUMELEM:
+ /* Funky: the value to set is under the [obj, id] pair. */
+ FETCH_ELEMENT_ID(-1, id);
+ lval = FETCH_OPND(-2);
+ VALUE_TO_OBJECT(cx, lval, obj);
+ rval = FETCH_OPND(-3);
+ SAVE_SP(fp);
+ ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
+ if (!ok)
+ goto out;
+ sp -= 3;
+ break;
+
+/*
+ * LAZY_ARGS_THISP allows the JSOP_ARGSUB bytecode to defer creation of the
+ * arguments object until it is truly needed. JSOP_ARGSUB optimizes away
+ * arguments objects when the only uses of the 'arguments' parameter are to
+ * fetch individual actual parameters. But if such a use were then invoked,
+ * e.g., arguments[i](), the 'this' parameter would and must bind to the
+ * caller's arguments object. So JSOP_ARGSUB sets obj to LAZY_ARGS_THISP.
+ */
+#define LAZY_ARGS_THISP ((JSObject *) 1)
+
+ case JSOP_PUSHOBJ:
+ if (obj == LAZY_ARGS_THISP && !(obj = js_GetArgsObject(cx, fp))) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ PUSH_OPND(OBJECT_TO_JSVAL(obj));
+ break;
+
+ case JSOP_CALL:
+ case JSOP_EVAL:
+ argc = GET_ARGC(pc);
+ vp = sp - (argc + 2);
+ lval = *vp;
+ SAVE_SP(fp);
+
+ if (JSVAL_IS_FUNCTION(cx, lval) &&
+ (obj = JSVAL_TO_OBJECT(lval),
+ fun = (JSFunction *) JS_GetPrivate(cx, obj),
+ !fun->native &&
+ !(fun->flags & (JSFUN_HEAVYWEIGHT | JSFUN_BOUND_METHOD)) &&
+ argc >= (uintN)(fun->nargs + fun->extra)))
+ /* inline_call: */
+ {
+ uintN nframeslots, nvars;
+ void *newmark;
+ JSInlineFrame *newifp;
+ JSInterpreterHook hook;
+
+ /* Restrict recursion of lightweight functions. */
+ if (inlineCallCount == MAX_INLINE_CALL_COUNT) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_OVER_RECURSED);
+ ok = JS_FALSE;
+ goto out;
+ }
+
+#if JS_HAS_JIT
+ /* ZZZbe should do this only if interpreted often enough. */
+ ok = jsjit_Compile(cx, fun);
+ if (!ok)
+ goto out;
+#endif
+
+ /* Compute the number of stack slots needed for fun. */
+ nframeslots = (sizeof(JSInlineFrame) + sizeof(jsval) - 1)
+ / sizeof(jsval);
+ nvars = fun->nvars;
+ script = fun->script;
+ depth = (jsint) script->depth;
+
+ /* Allocate the frame and space for vars and operands. */
+ newsp = js_AllocRawStack(cx, nframeslots + nvars + 2 * depth,
+ &newmark);
+ if (!newsp) {
+ ok = JS_FALSE;
+ goto bad_inline_call;
+ }
+ newifp = (JSInlineFrame *) newsp;
+ newsp += nframeslots;
+
+ /* Initialize the stack frame. */
+ memset(newifp, 0, sizeof(JSInlineFrame));
+ newifp->frame.script = script;
+ newifp->frame.fun = fun;
+ newifp->frame.argc = argc;
+ newifp->frame.argv = vp + 2;
+ newifp->frame.rval = JSVAL_VOID;
+ newifp->frame.nvars = nvars;
+ newifp->frame.vars = newsp;
+ newifp->frame.down = fp;
+ newifp->frame.scopeChain = OBJ_GET_PARENT(cx, obj);
+ newifp->mark = newmark;
+
+ /* Compute the 'this' parameter now that argv is set. */
+ ok = ComputeThis(cx, JSVAL_TO_OBJECT(vp[1]), &newifp->frame);
+ if (!ok) {
+ js_FreeRawStack(cx, newmark);
+ goto bad_inline_call;
+ }
+
+ /* Push void to initialize local variables. */
+ sp = newsp;
+ while (nvars--)
+ PUSH(JSVAL_VOID);
+ sp += depth;
+ newifp->frame.spbase = sp;
+ SAVE_SP(&newifp->frame);
+
+ /* Call the debugger hook if present. */
+ hook = cx->runtime->callHook;
+ if (hook) {
+ newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
+ cx->runtime->callHookData);
+ LOAD_INTERRUPT_HANDLER(rt);
+ }
+
+ /* Switch to new version if currentVersion wasn't overridden. */
+ newifp->callerVersion = cx->version;
+ if (cx->version == currentVersion) {
+ currentVersion = script->version;
+ if (currentVersion != cx->version)
+ JS_SetVersion(cx, currentVersion);
+ }
+
+ /* Push the frame and set interpreter registers. */
+ cx->fp = fp = &newifp->frame;
+ pc = script->code;
+ endpc = pc + script->length;
+ inlineCallCount++;
+ JS_RUNTIME_METER(rt, inlineCalls);
+ continue;
+
+ bad_inline_call:
+ script = fp->script;
+ depth = (jsint) script->depth;
+ goto out;
+ }
+
+ ok = js_Invoke(cx, argc, 0);
+ RESTORE_SP(fp);
+ LOAD_INTERRUPT_HANDLER(rt);
+ if (!ok)
+ goto out;
+ JS_RUNTIME_METER(rt, nonInlineCalls);
+#if JS_HAS_LVALUE_RETURN
+ if (cx->rval2set) {
+ /*
+ * Sneaky: use the stack depth we didn't claim in our budget,
+ * but that we know is there on account of [fun, this] already
+ * having been pushed, at a minimum (if no args). Those two
+ * slots have been popped and [rval] has been pushed, which
+ * leaves one more slot for rval2 before we might overflow.
+ *
+ * NB: rval2 must be the property identifier, and rval the
+ * object from which to get the property. The pair form an
+ * ECMA "reference type", which can be used on the right- or
+ * left-hand side of assignment ops. Only native methods can
+ * return reference types. See JSOP_SETCALL just below for
+ * the left-hand-side case.
+ */
+ PUSH_OPND(cx->rval2);
+ cx->rval2set = JS_FALSE;
+ ELEMENT_OP(-1, ok = OBJ_GET_PROPERTY(cx, obj, id, &rval));
+ sp--;
+ STORE_OPND(-1, rval);
+ }
+#endif
+ obj = NULL;
+ break;
+
+#if JS_HAS_LVALUE_RETURN
+ case JSOP_SETCALL:
+ argc = GET_ARGC(pc);
+ SAVE_SP(fp);
+ ok = js_Invoke(cx, argc, 0);
+ RESTORE_SP(fp);
+ LOAD_INTERRUPT_HANDLER(rt);
+ if (!ok)
+ goto out;
+ if (!cx->rval2set) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_LEFTSIDE_OF_ASS);
+ ok = JS_FALSE;
+ goto out;
+ }
+ PUSH_OPND(cx->rval2);
+ cx->rval2set = JS_FALSE;
+ obj = NULL;
+ break;
+#endif
+
+ case JSOP_NAME:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+
+ SAVE_SP(fp);
+ ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
+ if (!ok)
+ goto out;
+ if (!prop) {
+ /* Kludge to allow (typeof foo == "undefined") tests. */
+ for (pc2 = pc + len; pc2 < endpc; pc2++) {
+ op2 = (JSOp)*pc2;
+ if (op2 == JSOP_TYPEOF) {
+ PUSH_OPND(JSVAL_VOID);
+ goto advance_pc;
+ }
+ if (op2 != JSOP_GROUP)
+ break;
+ }
+ goto atom_not_defined;
+ }
+
+ /* Take the slow path if prop was not found in a native object. */
+ if (!OBJ_IS_NATIVE(obj) || !OBJ_IS_NATIVE(obj2)) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
+ if (!ok)
+ goto out;
+ PUSH_OPND(rval);
+ break;
+ }
+
+ /* Get and push the obj[id] property's value. */
+ sprop = (JSScopeProperty *)prop;
+ slot = (uintN)sprop->slot;
+ rval = (slot != SPROP_INVALID_SLOT)
+ ? LOCKED_OBJ_GET_SLOT(obj2, slot)
+ : JSVAL_VOID;
+ JS_UNLOCK_OBJ(cx, obj2);
+ ok = SPROP_GET(cx, sprop, obj, obj2, &rval);
+ JS_LOCK_OBJ(cx, obj2);
+ if (!ok) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ goto out;
+ }
+ if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2)))
+ LOCKED_OBJ_SET_SLOT(obj2, slot, rval);
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ PUSH_OPND(rval);
+ break;
+
+ case JSOP_UINT16:
+ i = (jsint) GET_ATOM_INDEX(pc);
+ rval = INT_TO_JSVAL(i);
+ PUSH_OPND(rval);
+ obj = NULL;
+ break;
+
+ case JSOP_NUMBER:
+ case JSOP_STRING:
+ atom = GET_ATOM(cx, script, pc);
+ PUSH_OPND(ATOM_KEY(atom));
+ obj = NULL;
+ break;
+
+ case JSOP_OBJECT:
+ {
+#if 0
+ jsatomid atomIndex;
+ JSAtomMap *atomMap;
+
+ /*
+ * Get a suitable object from an atom mapped by the bytecode at pc.
+ *
+ * We must handle the case where a regexp object literal is used in
+ * a different global at execution time from the global with which
+ * it was scanned at compile time, in order to rewrap the JSRegExp
+ * struct with a new object having the right prototype and parent.
+ *
+ * Unlike JSOP_DEFFUN and other prolog bytecodes, we don't want to
+ * pay a script prolog execution price for all regexp literals in a
+ * script (many may not be used by a particular execution of that
+ * script, depending on control flow), so we do all fp->objAtomMap
+ * initialization lazily, here under JSOP_OBJECT.
+ *
+ * XXX This code is specific to regular expression objects. If we
+ * need JSOP_OBJECT for other kinds of object literals, we should
+ * push cloning down under JSObjectOps. Also, fp->objAtomMap is
+ * used only for object atoms, so it's sparse (wasting some stack
+ * space) and as its name implies, you can't get non-object atoms
+ * from it.
+ */
+ atomIndex = GET_ATOM_INDEX(pc);
+ atomMap = fp->objAtomMap;
+ atom = atomMap ? atomMap->vector[atomIndex] : NULL;
+ if (!atom) {
+ /* Let atom and obj denote the regexp (object) mapped by pc. */
+ atom = js_GetAtom(cx, &script->atomMap, atomIndex);
+ JS_ASSERT(ATOM_IS_OBJECT(atom));
+ obj = ATOM_TO_OBJECT(atom);
+ JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
+
+ /* Compute the current global object in obj2. */
+ obj2 = fp->scopeChain;
+ while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL)
+ obj2 = parent;
+
+ /*
+ * If obj's parent is not obj2, we must clone obj so that it
+ * has the right parent, and therefore, the right prototype.
+ *
+ * Yes, this means we assume that the correct RegExp.prototype
+ * to which regexp instances (including literals) delegate can
+ * be distinguished solely by the instance's parent, which was
+ * set to the parent of the RegExp constructor function object
+ * when the instance was created. In other words,
+ *
+ * (/x/.__parent__ == RegExp.__parent__) implies
+ * (/x/.__proto__ == RegExp.prototype)
+ *
+ * (unless you assign a different object to RegExp.prototype
+ * at runtime, in which case, ECMA doesn't specify operation,
+ * and you get what you deserve).
+ *
+ * This same coupling between instance parent and constructor
+ * parent turns up elsewhere (see jsobj.c's FindConstructor,
+ * js_ConstructObject, and js_NewObject). It's fundamental.
+ */
+ if (OBJ_GET_PARENT(cx, obj) != obj2) {
+ obj = js_CloneRegExpObject(cx, obj, obj2);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ atom = js_AtomizeObject(cx, obj, 0);
+ if (!atom) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+
+ /*
+ * If fp->objAtomMap is null, initialize it now so we can map
+ * atom (whether atom is newly created for a cloned object, or
+ * the original atom mapped by script) for faster performance
+ * next time through JSOP_OBJECT.
+ */
+ if (!atomMap) {
+ jsatomid mapLength = script->atomMap.length;
+ size_t vectorBytes = mapLength * sizeof(JSAtom *);
+
+ /* Allocate an override atom map from cx->stackPool. */
+ JS_ARENA_ALLOCATE_CAST(atomMap, JSAtomMap *,
+ &cx->stackPool,
+ sizeof(JSAtomMap) + vectorBytes);
+ if (!atomMap) {
+ JS_ReportOutOfMemory(cx);
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ atomMap->length = mapLength;
+ atomMap->vector = (JSAtom **)(atomMap + 1);
+ memset(atomMap->vector, 0, vectorBytes);
+ fp->objAtomMap = atomMap;
+ }
+ atomMap->vector[atomIndex] = atom;
+ }
+#else
+ atom = GET_ATOM(cx, script, pc);
+ JS_ASSERT(ATOM_IS_OBJECT(atom));
+#endif
+ rval = ATOM_KEY(atom);
+ PUSH_OPND(rval);
+ obj = NULL;
+ break;
+ }
+
+ case JSOP_ZERO:
+ PUSH_OPND(JSVAL_ZERO);
+ obj = NULL;
+ break;
+
+ case JSOP_ONE:
+ PUSH_OPND(JSVAL_ONE);
+ obj = NULL;
+ break;
+
+ case JSOP_NULL:
+ PUSH_OPND(JSVAL_NULL);
+ obj = NULL;
+ break;
+
+ case JSOP_THIS:
+ PUSH_OPND(OBJECT_TO_JSVAL(fp->thisp));
+ obj = NULL;
+ break;
+
+ case JSOP_FALSE:
+ PUSH_OPND(JSVAL_FALSE);
+ obj = NULL;
+ break;
+
+ case JSOP_TRUE:
+ PUSH_OPND(JSVAL_TRUE);
+ obj = NULL;
+ break;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case JSOP_TABLESWITCH:
+ pc2 = pc;
+ len = GET_JUMP_OFFSET(pc2);
+
+ /*
+ * ECMAv2 forbids conversion of discriminant, so we will skip to
+ * the default case if the discriminant isn't already an int jsval.
+ * (This opcode is emitted only for dense jsint-domain switches.)
+ */
+ if (cx->version == JSVERSION_DEFAULT ||
+ cx->version >= JSVERSION_1_4) {
+ rval = POP_OPND();
+ if (!JSVAL_IS_INT(rval))
+ break;
+ i = JSVAL_TO_INT(rval);
+ } else {
+ FETCH_INT(cx, -1, i);
+ sp--;
+ }
+
+ pc2 += JUMP_OFFSET_LEN;
+ low = GET_JUMP_OFFSET(pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ high = GET_JUMP_OFFSET(pc2);
+
+ i -= low;
+ if ((jsuint)i < (jsuint)(high - low + 1)) {
+ pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
+ off = (jsint) GET_JUMP_OFFSET(pc2);
+ if (off)
+ len = off;
+ }
+ break;
+
+ case JSOP_LOOKUPSWITCH:
+ lval = POP_OPND();
+ pc2 = pc;
+ len = GET_JUMP_OFFSET(pc2);
+
+ if (!JSVAL_IS_NUMBER(lval) &&
+ !JSVAL_IS_STRING(lval) &&
+ !JSVAL_IS_BOOLEAN(lval)) {
+ goto advance_pc;
+ }
+
+ pc2 += JUMP_OFFSET_LEN;
+ npairs = (jsint) GET_ATOM_INDEX(pc2);
+ pc2 += ATOM_INDEX_LEN;
+
+#define SEARCH_PAIRS(MATCH_CODE) \
+ while (npairs) { \
+ atom = GET_ATOM(cx, script, pc2); \
+ rval = ATOM_KEY(atom); \
+ MATCH_CODE \
+ if (match) { \
+ pc2 += ATOM_INDEX_LEN; \
+ len = GET_JUMP_OFFSET(pc2); \
+ goto advance_pc; \
+ } \
+ pc2 += ATOM_INDEX_LEN + JUMP_OFFSET_LEN; \
+ npairs--; \
+ }
+ if (JSVAL_IS_STRING(lval)) {
+ str = JSVAL_TO_STRING(lval);
+ SEARCH_PAIRS(
+ match = (JSVAL_IS_STRING(rval) &&
+ ((str2 = JSVAL_TO_STRING(rval)) == str ||
+ !js_CompareStrings(str2, str)));
+ )
+ } else if (JSVAL_IS_DOUBLE(lval)) {
+ d = *JSVAL_TO_DOUBLE(lval);
+ SEARCH_PAIRS(
+ match = (JSVAL_IS_DOUBLE(rval) &&
+ *JSVAL_TO_DOUBLE(rval) == d);
+ )
+ } else {
+ SEARCH_PAIRS(
+ match = (lval == rval);
+ )
+ }
+#undef SEARCH_PAIRS
+ break;
+
+ case JSOP_TABLESWITCHX:
+ pc2 = pc;
+ len = GET_JUMPX_OFFSET(pc2);
+
+ /*
+ * ECMAv2 forbids conversion of discriminant, so we will skip to
+ * the default case if the discriminant isn't already an int jsval.
+ * (This opcode is emitted only for dense jsint-domain switches.)
+ */
+ if (cx->version == JSVERSION_DEFAULT ||
+ cx->version >= JSVERSION_1_4) {
+ rval = POP_OPND();
+ if (!JSVAL_IS_INT(rval))
+ break;
+ i = JSVAL_TO_INT(rval);
+ } else {
+ FETCH_INT(cx, -1, i);
+ sp--;
+ }
+
+ pc2 += JUMPX_OFFSET_LEN;
+ low = GET_JUMP_OFFSET(pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ high = GET_JUMP_OFFSET(pc2);
+
+ i -= low;
+ if ((jsuint)i < (jsuint)(high - low + 1)) {
+ pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i;
+ off = (jsint) GET_JUMPX_OFFSET(pc2);
+ if (off)
+ len = off;
+ }
+ break;
+
+ case JSOP_LOOKUPSWITCHX:
+ lval = POP_OPND();
+ pc2 = pc;
+ len = GET_JUMPX_OFFSET(pc2);
+
+ if (!JSVAL_IS_NUMBER(lval) &&
+ !JSVAL_IS_STRING(lval) &&
+ !JSVAL_IS_BOOLEAN(lval)) {
+ goto advance_pc;
+ }
+
+ pc2 += JUMPX_OFFSET_LEN;
+ npairs = (jsint) GET_ATOM_INDEX(pc2);
+ pc2 += ATOM_INDEX_LEN;
+
+#define SEARCH_EXTENDED_PAIRS(MATCH_CODE) \
+ while (npairs) { \
+ atom = GET_ATOM(cx, script, pc2); \
+ rval = ATOM_KEY(atom); \
+ MATCH_CODE \
+ if (match) { \
+ pc2 += ATOM_INDEX_LEN; \
+ len = GET_JUMPX_OFFSET(pc2); \
+ goto advance_pc; \
+ } \
+ pc2 += ATOM_INDEX_LEN + JUMPX_OFFSET_LEN; \
+ npairs--; \
+ }
+ if (JSVAL_IS_STRING(lval)) {
+ str = JSVAL_TO_STRING(lval);
+ SEARCH_EXTENDED_PAIRS(
+ match = (JSVAL_IS_STRING(rval) &&
+ ((str2 = JSVAL_TO_STRING(rval)) == str ||
+ !js_CompareStrings(str2, str)));
+ )
+ } else if (JSVAL_IS_DOUBLE(lval)) {
+ d = *JSVAL_TO_DOUBLE(lval);
+ SEARCH_EXTENDED_PAIRS(
+ match = (JSVAL_IS_DOUBLE(rval) &&
+ *JSVAL_TO_DOUBLE(rval) == d);
+ )
+ } else {
+ SEARCH_EXTENDED_PAIRS(
+ match = (lval == rval);
+ )
+ }
+#undef SEARCH_EXTENDED_PAIRS
+ break;
+
+ case JSOP_CONDSWITCH:
+ break;
+
+#endif /* JS_HAS_SWITCH_STATEMENT */
+
+#if JS_HAS_EXPORT_IMPORT
+ case JSOP_EXPORTALL:
+ obj = fp->varobj;
+ ida = JS_Enumerate(cx, obj);
+ if (!ida) {
+ ok = JS_FALSE;
+ } else {
+ for (i = 0, j = ida->length; i < j; i++) {
+ id = ida->vector[i];
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
+ if (!ok)
+ break;
+ if (!prop)
+ continue;
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
+ if (ok) {
+ attrs |= JSPROP_EXPORTED;
+ ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ if (!ok)
+ break;
+ }
+ JS_DestroyIdArray(cx, ida);
+ }
+ break;
+
+ case JSOP_EXPORTNAME:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ obj = fp->varobj;
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
+ if (!ok)
+ goto out;
+ if (!prop) {
+ ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
+ JSPROP_EXPORTED, NULL);
+ } else {
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
+ if (ok) {
+ attrs |= JSPROP_EXPORTED;
+ ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ }
+ if (!ok)
+ goto out;
+ break;
+
+ case JSOP_IMPORTALL:
+ id = (jsid)JSVAL_VOID;
+ PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
+ sp--;
+ break;
+
+ case JSOP_IMPORTPROP:
+ /* Get an immediate atom naming the property. */
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
+ sp--;
+ break;
+
+ case JSOP_IMPORTELEM:
+ ELEMENT_OP(-1, ok = ImportProperty(cx, obj, id));
+ sp -= 2;
+ break;
+#endif /* JS_HAS_EXPORT_IMPORT */
+
+ case JSOP_TRAP:
+ switch (JS_HandleTrap(cx, script, pc, &rval)) {
+ case JSTRAP_ERROR:
+ ok = JS_FALSE;
+ goto out;
+ case JSTRAP_CONTINUE:
+ JS_ASSERT(JSVAL_IS_INT(rval));
+ op = (JSOp) JSVAL_TO_INT(rval);
+ JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
+ LOAD_INTERRUPT_HANDLER(rt);
+ goto do_op;
+ case JSTRAP_RETURN:
+ fp->rval = rval;
+ goto out;
+#if JS_HAS_EXCEPTIONS
+ case JSTRAP_THROW:
+ cx->throwing = JS_TRUE;
+ cx->exception = rval;
+ ok = JS_FALSE;
+ goto out;
+#endif /* JS_HAS_EXCEPTIONS */
+ default:;
+ }
+ LOAD_INTERRUPT_HANDLER(rt);
+ break;
+
+ case JSOP_ARGUMENTS:
+ SAVE_SP(fp);
+ ok = js_GetArgsValue(cx, fp, &rval);
+ if (!ok)
+ goto out;
+ PUSH_OPND(rval);
+ break;
+
+ case JSOP_ARGSUB:
+ id = (jsid) INT_TO_JSVAL(GET_ARGNO(pc));
+ SAVE_SP(fp);
+ ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
+ if (!ok)
+ goto out;
+ if (!obj) {
+ /*
+ * If arguments was not overridden by eval('arguments = ...'),
+ * set obj to the magic cookie respected by JSOP_PUSHOBJ, just
+ * in case this bytecode is part of an 'arguments[i](j, k)' or
+ * similar such invocation sequence, where the function that
+ * is invoked expects its 'this' parameter to be the caller's
+ * arguments object.
+ */
+ obj = LAZY_ARGS_THISP;
+ }
+ PUSH_OPND(rval);
+ break;
+
+#undef LAZY_ARGS_THISP
+
+ case JSOP_ARGCNT:
+ id = (jsid) rt->atomState.lengthAtom;
+ SAVE_SP(fp);
+ ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
+ if (!ok)
+ goto out;
+ PUSH_OPND(rval);
+ break;
+
+ case JSOP_GETARG:
+ slot = GET_ARGNO(pc);
+ JS_ASSERT(slot < fp->fun->nargs);
+ PUSH_OPND(fp->argv[slot]);
+ obj = NULL;
+ break;
+
+ case JSOP_SETARG:
+ slot = GET_ARGNO(pc);
+ JS_ASSERT(slot < fp->fun->nargs);
+ vp = &fp->argv[slot];
+ GC_POKE(cx, *vp);
+ *vp = FETCH_OPND(-1);
+ obj = NULL;
+ break;
+
+ case JSOP_GETVAR:
+ slot = GET_VARNO(pc);
+ JS_ASSERT(slot < fp->fun->nvars);
+ PUSH_OPND(fp->vars[slot]);
+ obj = NULL;
+ break;
+
+ case JSOP_SETVAR:
+ slot = GET_VARNO(pc);
+ JS_ASSERT(slot < fp->fun->nvars);
+ vp = &fp->vars[slot];
+ GC_POKE(cx, *vp);
+ *vp = FETCH_OPND(-1);
+ obj = NULL;
+ break;
+
+ case JSOP_DEFCONST:
+ case JSOP_DEFVAR:
+ {
+ JSBool defined;
+
+ atom = GET_ATOM(cx, script, pc);
+ obj = fp->varobj;
+ attrs = JSPROP_ENUMERATE;
+ if (!(fp->flags & JSFRAME_EVAL))
+ attrs |= JSPROP_PERMANENT;
+ if (op == JSOP_DEFCONST)
+ attrs |= JSPROP_READONLY;
+
+ /* Lookup id in order to check for redeclaration problems. */
+ id = (jsid)atom;
+ ok = js_CheckRedeclaration(cx, obj, id, attrs, &defined);
+ if (!ok)
+ goto out;
+
+ /* Bind a variable only if it's not yet defined. */
+ if (!defined) {
+ ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
+ attrs, NULL);
+ if (!ok)
+ goto out;
+ }
+ break;
+ }
+
+ case JSOP_DEFFUN:
+ {
+ uintN flags;
+
+ atom = GET_ATOM(cx, script, pc);
+ obj = ATOM_TO_OBJECT(atom);
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ id = (jsid) fun->atom;
+
+ /*
+ * We must be at top-level (either outermost block that forms a
+ * function's body, or a global) scope, not inside an expression
+ * (JSOP_{ANON,NAMED}FUNOBJ) or compound statement (JSOP_CLOSURE)
+ * in the same compilation unit (ECMA Program).
+ *
+ * However, we could be in a Program being eval'd from inside a
+ * with statement, so we need to distinguish variables object from
+ * scope chain head. Hence the two assignments to parent below.
+ * First we make sure the function object we're defining has the
+ * right scope chain. Then we define its name in fp->varobj.
+ *
+ * If static link is not current scope, clone fun's object to link
+ * to the current scope via parent. This clause exists to enable
+ * sharing of compiled functions among multiple equivalent scopes,
+ * splitting the cost of compilation evenly among the scopes and
+ * amortizing it over a number of executions. Examples include XUL
+ * scripts and event handlers shared among Mozilla chrome windows,
+ * and server-side JS user-defined functions shared among requests.
+ *
+ * NB: The Script object exposes compile and exec in the language,
+ * such that this clause introduces an incompatible change from old
+ * JS versions that supported Script. Such a JS version supported
+ * executing a script that defined and called functions scoped by
+ * the compile-time static link, not by the exec-time scope chain.
+ *
+ * We sacrifice compatibility, breaking such scripts, in order to
+ * promote compile-cost sharing and amortizing, and because Script
+ * is not and will not be standardized.
+ */
+ parent = fp->scopeChain;
+ if (OBJ_GET_PARENT(cx, obj) != parent) {
+ obj = js_CloneFunctionObject(cx, obj, parent);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+
+ /*
+ * ECMA requires functions defined when entering Global code to be
+ * permanent, and functions defined when entering Eval code to be
+ * impermanent.
+ */
+ attrs = JSPROP_ENUMERATE;
+ if (!(fp->flags & JSFRAME_EVAL))
+ attrs |= JSPROP_PERMANENT;
+
+ /*
+ * Load function flags that are also property attributes. Getters
+ * and setters do not need a slot, their value is stored elsewhere
+ * in the property itself, not in obj->slots.
+ */
+ flags = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
+ if (flags)
+ attrs |= flags | JSPROP_SHARED;
+
+ /*
+ * Check for a const property of the same name -- or any kind
+ * of property if executing with the strict option. We check
+ * here at runtime as well as at compile-time, to handle eval
+ * as well as multiple HTML script tags.
+ */
+ parent = fp->varobj;
+ ok = js_CheckRedeclaration(cx, parent, id, attrs, &cond);
+ if (!ok)
+ goto out;
+
+ ok = OBJ_DEFINE_PROPERTY(cx, parent, id,
+ flags ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
+ (flags & JSFUN_GETTER)
+ ? (JSPropertyOp) obj
+ : NULL,
+ (flags & JSFUN_SETTER)
+ ? (JSPropertyOp) obj
+ : NULL,
+ attrs,
+ NULL);
+ if (!ok)
+ goto out;
+ break;
+ }
+
+#if JS_HAS_LEXICAL_CLOSURE
+ case JSOP_DEFLOCALFUN:
+ /*
+ * Define a local function (i.e., one nested at the top level of
+ * another function), parented by the current scope chain, and
+ * stored in a local variable slot that the compiler allocated.
+ * This is an optimization over JSOP_DEFFUN that avoids requiring
+ * a call object for the outer function's activation.
+ */
+ pc2 = pc;
+ slot = GET_VARNO(pc2);
+ pc2 += VARNO_LEN;
+ atom = GET_ATOM(cx, script, pc2);
+ obj = ATOM_TO_OBJECT(atom);
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+
+ parent = fp->scopeChain;
+ if (OBJ_GET_PARENT(cx, obj) != parent) {
+ obj = js_CloneFunctionObject(cx, obj, parent);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+ fp->vars[slot] = OBJECT_TO_JSVAL(obj);
+ break;
+
+ case JSOP_ANONFUNOBJ:
+ /* Push the specified function object literal. */
+ atom = GET_ATOM(cx, script, pc);
+ obj = ATOM_TO_OBJECT(atom);
+
+ /* If re-parenting, push a clone of the function object. */
+ parent = fp->scopeChain;
+ if (OBJ_GET_PARENT(cx, obj) != parent) {
+ obj = js_CloneFunctionObject(cx, obj, parent);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+ PUSH_OPND(OBJECT_TO_JSVAL(obj));
+ break;
+
+ case JSOP_NAMEDFUNOBJ:
+ /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
+ atom = GET_ATOM(cx, script, pc);
+ rval = ATOM_KEY(atom);
+ JS_ASSERT(JSVAL_IS_FUNCTION(cx, rval));
+
+ /*
+ * 1. Create a new object as if by the expression new Object().
+ * 2. Add Result(1) to the front of the scope chain.
+ *
+ * Step 2 is achieved by making the new object's parent be the
+ * current scope chain, and then making the new object the parent
+ * of the Function object clone.
+ */
+ SAVE_SP(fp);
+ parent = js_ConstructObject(cx, &js_ObjectClass, NULL,
+ fp->scopeChain, 0, NULL);
+ if (!parent) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ /*
+ * 3. Create a new Function object as specified in section 13.2
+ * with [parameters and body specified by the function expression
+ * that was parsed by the compiler into a Function object, and
+ * saved in the script's atom map].
+ */
+ obj = js_CloneFunctionObject(cx, JSVAL_TO_OBJECT(rval), parent);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ /*
+ * 4. Create a property in the object Result(1). The property's
+ * name is [fun->atom, the identifier parsed by the compiler],
+ * value is Result(3), and attributes are { DontDelete, ReadOnly }.
+ */
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
+ if (attrs)
+ attrs |= JSPROP_SHARED;
+ ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom,
+ attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
+ (attrs & JSFUN_GETTER)
+ ? (JSPropertyOp) obj
+ : NULL,
+ (attrs & JSFUN_SETTER)
+ ? (JSPropertyOp) obj
+ : NULL,
+ attrs |
+ JSPROP_ENUMERATE | JSPROP_PERMANENT |
+ JSPROP_READONLY,
+ NULL);
+ if (!ok) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ goto out;
+ }
+
+ /*
+ * 5. Remove Result(1) from the front of the scope chain [no-op].
+ * 6. Return Result(3).
+ */
+ PUSH_OPND(OBJECT_TO_JSVAL(obj));
+ break;
+
+ case JSOP_CLOSURE:
+ /*
+ * ECMA ed. 3 extension: a named function expression in a compound
+ * statement (not at the top statement level of global code, or at
+ * the top level of a function body).
+ *
+ * Get immediate operand atom, which is a function object literal.
+ * From it, get the function to close.
+ */
+ atom = GET_ATOM(cx, script, pc);
+ JS_ASSERT(JSVAL_IS_FUNCTION(cx, ATOM_KEY(atom)));
+ obj = ATOM_TO_OBJECT(atom);
+
+ /*
+ * Clone the function object with the current scope chain as the
+ * clone's parent. The original function object is the prototype
+ * of the clone. Do this only if re-parenting; the compiler may
+ * have seen the right parent already and created a sufficiently
+ * well-scoped function object.
+ */
+ parent = fp->scopeChain;
+ if (OBJ_GET_PARENT(cx, obj) != parent) {
+ obj = js_CloneFunctionObject(cx, obj, parent);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+
+ /*
+ * Make a property in fp->varobj with id fun->atom and value obj,
+ * unless fun is a getter or setter (in which case, obj is cast to
+ * a JSPropertyOp and passed accordingly).
+ */
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
+ if (attrs)
+ attrs |= JSPROP_SHARED;
+ ok = OBJ_DEFINE_PROPERTY(cx, fp->varobj, (jsid)fun->atom,
+ attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
+ (attrs & JSFUN_GETTER)
+ ? (JSPropertyOp) obj
+ : NULL,
+ (attrs & JSFUN_SETTER)
+ ? (JSPropertyOp) obj
+ : NULL,
+ attrs | JSPROP_ENUMERATE,
+ NULL);
+ if (!ok) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ goto out;
+ }
+ break;
+#endif /* JS_HAS_LEXICAL_CLOSURE */
+
+#if JS_HAS_GETTER_SETTER
+ case JSOP_GETTER:
+ case JSOP_SETTER:
+ JS_ASSERT(len == 1);
+ op2 = (JSOp) *++pc;
+ cs = &js_CodeSpec[op2];
+ len = cs->length;
+ switch (op2) {
+ case JSOP_SETNAME:
+ case JSOP_SETPROP:
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ i = -1;
+ rval = FETCH_OPND(i);
+ goto gs_pop_lval;
+
+ case JSOP_SETELEM:
+ rval = FETCH_OPND(-1);
+ i = -2;
+ FETCH_ELEMENT_ID(i, id);
+ gs_pop_lval:
+ lval = FETCH_OPND(i-1);
+ VALUE_TO_OBJECT(cx, lval, obj);
+ break;
+
+#if JS_HAS_INITIALIZERS
+ case JSOP_INITPROP:
+ JS_ASSERT(sp - fp->spbase >= 2);
+ i = -1;
+ rval = FETCH_OPND(i);
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ goto gs_get_lval;
+
+ case JSOP_INITELEM:
+ JS_ASSERT(sp - fp->spbase >= 3);
+ rval = FETCH_OPND(-1);
+ i = -2;
+ FETCH_ELEMENT_ID(i, id);
+ gs_get_lval:
+ lval = FETCH_OPND(i-1);
+ JS_ASSERT(JSVAL_IS_OBJECT(lval));
+ obj = JSVAL_TO_OBJECT(lval);
+ break;
+#endif /* JS_HAS_INITIALIZERS */
+
+ default:
+ JS_ASSERT(0);
+ }
+
+ if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_GETTER_OR_SETTER,
+ (op == JSOP_GETTER)
+ ? js_getter_str
+ : js_setter_str);
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ /*
+ * Getters and setters are just like watchpoints from an access
+ * control point of view.
+ */
+ ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs);
+ if (!ok)
+ goto out;
+
+ if (op == JSOP_GETTER) {
+ getter = (JSPropertyOp) JSVAL_TO_OBJECT(rval);
+ setter = NULL;
+ attrs = JSPROP_GETTER;
+ } else {
+ getter = NULL;
+ setter = (JSPropertyOp) JSVAL_TO_OBJECT(rval);
+ attrs = JSPROP_SETTER;
+ }
+ attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
+
+ /* Check for a readonly or permanent property of the same name. */
+ ok = js_CheckRedeclaration(cx, obj, id, attrs, &cond);
+ if (!ok)
+ goto out;
+
+ ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter,
+ attrs, NULL);
+ if (!ok)
+ goto out;
+
+ sp += i;
+ if (cs->ndefs)
+ STORE_OPND(-1, rval);
+ break;
+#endif /* JS_HAS_GETTER_SETTER */
+
+#if JS_HAS_INITIALIZERS
+ case JSOP_NEWINIT:
+ argc = 0;
+ fp->sharpDepth++;
+ goto do_new;
+
+ case JSOP_ENDINIT:
+ if (--fp->sharpDepth == 0)
+ fp->sharpArray = NULL;
+
+ /* Re-set the newborn root to the top of this object tree. */
+ JS_ASSERT(sp - fp->spbase >= 1);
+ lval = FETCH_OPND(-1);
+ JS_ASSERT(JSVAL_IS_OBJECT(lval));
+ cx->newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval);
+ break;
+
+ case JSOP_INITPROP:
+ /* Pop the property's value into rval. */
+ JS_ASSERT(sp - fp->spbase >= 2);
+ rval = FETCH_OPND(-1);
+
+ /* Get the immediate property name into id. */
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+ i = -1;
+ goto do_init;
+
+ case JSOP_INITELEM:
+ /* Pop the element's value into rval. */
+ JS_ASSERT(sp - fp->spbase >= 3);
+ rval = FETCH_OPND(-1);
+
+ /* Pop and conditionally atomize the element id. */
+ FETCH_ELEMENT_ID(-2, id);
+ i = -2;
+
+ do_init:
+ /* Find the object being initialized at top of stack. */
+ lval = FETCH_OPND(i-1);
+ JS_ASSERT(JSVAL_IS_OBJECT(lval));
+ obj = JSVAL_TO_OBJECT(lval);
+
+ /* Set the property named by obj[id] to rval. */
+ ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
+ if (!ok)
+ goto out;
+ sp += i;
+ break;
+
+#if JS_HAS_SHARP_VARS
+ case JSOP_DEFSHARP:
+ obj = fp->sharpArray;
+ if (!obj) {
+ obj = js_NewArrayObject(cx, 0, NULL);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ fp->sharpArray = obj;
+ }
+ i = (jsint) GET_ATOM_INDEX(pc);
+ id = (jsid) INT_TO_JSVAL(i);
+ rval = FETCH_OPND(-1);
+ if (JSVAL_IS_PRIMITIVE(rval)) {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_SHARP_DEF, numBuf);
+ ok = JS_FALSE;
+ goto out;
+ }
+ ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
+ if (!ok)
+ goto out;
+ break;
+
+ case JSOP_USESHARP:
+ i = (jsint) GET_ATOM_INDEX(pc);
+ id = (jsid) INT_TO_JSVAL(i);
+ obj = fp->sharpArray;
+ if (!obj) {
+ rval = JSVAL_VOID;
+ } else {
+ ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
+ if (!ok)
+ goto out;
+ }
+ if (!JSVAL_IS_OBJECT(rval)) {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_SHARP_USE, numBuf);
+ ok = JS_FALSE;
+ goto out;
+ }
+ PUSH_OPND(rval);
+ break;
+#endif /* JS_HAS_SHARP_VARS */
+#endif /* JS_HAS_INITIALIZERS */
+
+#if JS_HAS_EXCEPTIONS
+ /* No-ops for ease of decompilation and jit'ing. */
+ case JSOP_TRY:
+ case JSOP_FINALLY:
+ break;
+
+ /* Reset the stack to the given depth. */
+ case JSOP_SETSP:
+ i = (jsint) GET_ATOM_INDEX(pc);
+ JS_ASSERT(i >= 0);
+ sp = fp->spbase + i;
+ break;
+
+ case JSOP_GOSUB:
+ i = PTRDIFF(pc, script->main, jsbytecode) + len;
+ len = GET_JUMP_OFFSET(pc);
+ PUSH(INT_TO_JSVAL(i));
+ break;
+
+ case JSOP_GOSUBX:
+ i = PTRDIFF(pc, script->main, jsbytecode) + len;
+ len = GET_JUMPX_OFFSET(pc);
+ PUSH(INT_TO_JSVAL(i));
+ break;
+
+ case JSOP_RETSUB:
+ rval = POP();
+ JS_ASSERT(JSVAL_IS_INT(rval));
+ i = JSVAL_TO_INT(rval);
+ pc = script->main + i;
+ len = 0;
+ break;
+
+ case JSOP_EXCEPTION:
+ PUSH(cx->exception);
+ break;
+
+ case JSOP_THROW:
+ cx->throwing = JS_TRUE;
+ cx->exception = POP_OPND();
+ ok = JS_FALSE;
+ /* let the code at out try to catch the exception. */
+ goto out;
+
+ case JSOP_INITCATCHVAR:
+ /* Pop the property's value into rval. */
+ JS_ASSERT(sp - fp->spbase >= 2);
+ rval = POP_OPND();
+
+ /* Get the immediate catch variable name into id. */
+ atom = GET_ATOM(cx, script, pc);
+ id = (jsid)atom;
+
+ /* Find the object being initialized at top of stack. */
+ lval = FETCH_OPND(-1);
+ JS_ASSERT(JSVAL_IS_OBJECT(lval));
+ obj = JSVAL_TO_OBJECT(lval);
+
+ /* Define obj[id] to contain rval and to be permanent. */
+ ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
+ JSPROP_PERMANENT, NULL);
+ if (!ok)
+ goto out;
+ break;
+#endif /* JS_HAS_EXCEPTIONS */
+
+#if JS_HAS_INSTANCEOF
+ case JSOP_INSTANCEOF:
+ rval = FETCH_OPND(-1);
+ if (JSVAL_IS_PRIMITIVE(rval)) {
+ SAVE_SP(fp);
+ str = js_DecompileValueGenerator(cx, -1, rval, NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_INSTANCEOF_RHS,
+ JS_GetStringBytes(str));
+ }
+ ok = JS_FALSE;
+ goto out;
+ }
+ obj = JSVAL_TO_OBJECT(rval);
+ lval = FETCH_OPND(-2);
+ cond = JS_FALSE;
+ if (obj->map->ops->hasInstance) {
+ SAVE_SP(fp);
+ ok = obj->map->ops->hasInstance(cx, obj, lval, &cond);
+ if (!ok)
+ goto out;
+ }
+ sp--;
+ STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
+ break;
+#endif /* JS_HAS_INSTANCEOF */
+
+#if JS_HAS_DEBUGGER_KEYWORD
+ case JSOP_DEBUGGER:
+ {
+ JSTrapHandler handler = rt->debuggerHandler;
+ if (handler) {
+ SAVE_SP(fp);
+ switch (handler(cx, script, pc, &rval,
+ rt->debuggerHandlerData)) {
+ case JSTRAP_ERROR:
+ ok = JS_FALSE;
+ goto out;
+ case JSTRAP_CONTINUE:
+ break;
+ case JSTRAP_RETURN:
+ fp->rval = rval;
+ goto out;
+#if JS_HAS_EXCEPTIONS
+ case JSTRAP_THROW:
+ cx->throwing = JS_TRUE;
+ cx->exception = rval;
+ ok = JS_FALSE;
+ goto out;
+#endif /* JS_HAS_EXCEPTIONS */
+ default:;
+ }
+ LOAD_INTERRUPT_HANDLER(rt);
+ }
+ break;
+ }
+#endif /* JS_HAS_DEBUGGER_KEYWORD */
+
+ default: {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%d", op);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_BYTECODE, numBuf);
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+
+ advance_pc:
+ pc += len;
+
+#ifdef DEBUG
+ if (tracefp) {
+ intN ndefs, n;
+ jsval *siter;
+
+ ndefs = cs->ndefs;
+ if (ndefs) {
+ SAVE_SP(fp);
+ for (n = -ndefs; n < 0; n++) {
+ str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
+ if (str) {
+ fprintf(tracefp, "%s %s",
+ (n == -ndefs) ? " output:" : ",",
+ JS_GetStringBytes(str));
+ }
+ }
+ fprintf(tracefp, " @ %d\n", sp - fp->spbase);
+ }
+ fprintf(tracefp, " stack: ");
+ for (siter = fp->spbase; siter < sp; siter++) {
+ str = js_ValueToSource(cx, *siter);
+ fprintf(tracefp, "%s ",
+ str ? JS_GetStringBytes(str) : "<null>");
+ }
+ fputc('\n', tracefp);
+ }
+#endif
+ }
+out:
+
+#if JS_HAS_EXCEPTIONS
+ /*
+ * Has an exception been raised?
+ */
+ if (!ok && cx->throwing) {
+ /*
+ * Call debugger throw hook if set (XXX thread safety?).
+ */
+ JSTrapHandler handler = rt->throwHook;
+ if (handler) {
+ SAVE_SP(fp);
+ switch (handler(cx, script, pc, &rval, rt->throwHookData)) {
+ case JSTRAP_ERROR:
+ cx->throwing = JS_FALSE;
+ goto no_catch;
+ case JSTRAP_RETURN:
+ ok = JS_TRUE;
+ cx->throwing = JS_FALSE;
+ fp->rval = rval;
+ goto no_catch;
+ case JSTRAP_THROW:
+ cx->exception = rval;
+ case JSTRAP_CONTINUE:
+ default:;
+ }
+ LOAD_INTERRUPT_HANDLER(rt);
+ }
+
+ /*
+ * Look for a try block within this frame that can catch the exception.
+ */
+ SCRIPT_FIND_CATCH_START(script, pc, pc);
+ if (pc) {
+ len = 0;
+ cx->throwing = JS_FALSE; /* caught */
+ ok = JS_TRUE;
+ goto advance_pc;
+ }
+ }
+no_catch:
+#endif
+
+ /*
+ * Check whether control fell off the end of a lightweight function, or an
+ * exception thrown under such a function was not caught by it. If so, go
+ * to the inline code under JSOP_RETURN.
+ */
+ if (inlineCallCount)
+ goto inline_return;
+
+ /*
+ * Reset sp before freeing stack slots, because our caller may GC soon.
+ * Clear spbase to indicate that we've popped the 2 * depth operand slots.
+ * Restore the previous frame's execution state.
+ */
+ fp->sp = fp->spbase;
+ fp->spbase = NULL;
+ js_FreeRawStack(cx, mark);
+ if (cx->version == currentVersion && currentVersion != originalVersion)
+ JS_SetVersion(cx, originalVersion);
+ cx->interpLevel--;
+ return ok;
+
+atom_not_defined:
+ {
+ const char *printable = js_AtomToPrintableString(cx, atom);
+ if (printable)
+ js_ReportIsNotDefined(cx, printable);
+ ok = JS_FALSE;
+ goto out;
+ }
+}
diff --git a/src/dom/js/jsinterp.h b/src/dom/js/jsinterp.h
new file mode 100644
index 000000000..3e0634e4d
--- /dev/null
+++ b/src/dom/js/jsinterp.h
@@ -0,0 +1,292 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsinterp_h___
+#define jsinterp_h___
+/*
+ * JS interpreter interface.
+ */
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * JS stack frame, allocated on the C stack.
+ */
+struct JSStackFrame {
+ JSObject *callobj; /* lazily created Call object */
+ JSObject *argsobj; /* lazily created arguments object */
+ JSObject *varobj; /* variables object, where vars go */
+ JSScript *script; /* script being interpreted */
+ JSFunction *fun; /* function being called or null */
+ JSObject *thisp; /* "this" pointer if in method */
+ uintN argc; /* actual argument count */
+ jsval *argv; /* base of argument stack slots */
+ jsval rval; /* function return value */
+ uintN nvars; /* local variable count */
+ jsval *vars; /* base of variable stack slots */
+ JSStackFrame *down; /* previous frame */
+ void *annotation; /* used by Java security */
+ JSObject *scopeChain; /* scope chain */
+ jsbytecode *pc; /* program counter */
+ jsval *sp; /* stack pointer */
+ jsval *spbase; /* operand stack base */
+ uintN sharpDepth; /* array/object initializer depth */
+ JSObject *sharpArray; /* scope for #n= initializer vars */
+ uint32 flags; /* frame flags -- see below */
+ JSStackFrame *dormantNext; /* next dormant frame chain */
+ JSAtomMap *objAtomMap; /* object atom map, non-null only if we
+ hit a regexp object literal */
+};
+
+typedef struct JSInlineFrame {
+ JSStackFrame frame; /* base struct */
+ void *mark; /* mark before inline frame */
+ void *hookData; /* debugger call hook data */
+ JSVersion callerVersion; /* dynamic version of calling script */
+} JSInlineFrame;
+
+/* JS stack frame flags. */
+#define JSFRAME_CONSTRUCTING 0x01 /* frame is for a constructor invocation */
+#define JSFRAME_INTERNAL 0x02 /* internal call, not invoked by a script */
+#define JSFRAME_SKIP_CALLER 0x04 /* skip one link when evaluating f.caller
+ for this invocation of f */
+#define JSFRAME_ASSIGNING 0x08 /* a complex (not simplex JOF_ASSIGNING) op
+ is currently assigning to a property */
+#define JSFRAME_DEBUGGER 0x10 /* frame for JS_EvaluateInStackFrame */
+#define JSFRAME_EVAL 0x20 /* frame for obj_eval */
+#define JSFRAME_SPECIAL 0x30 /* special evaluation frame flags */
+
+#define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */
+#define JSFRAME_OVERRIDE_BITS 8
+
+/*
+ * Property cache for quickened get/set property opcodes.
+ */
+#define PROPERTY_CACHE_LOG2 10
+#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2)
+#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2)
+
+#define PROPERTY_CACHE_HASH(obj, id) \
+ ((((jsuword)(obj) >> JSVAL_TAGBITS) ^ (jsuword)(id)) & PROPERTY_CACHE_MASK)
+
+#ifdef JS_THREADSAFE
+
+#if HAVE_ATOMIC_DWORD_ACCESS
+
+#define PCE_LOAD(cache, pce, entry) JS_ATOMIC_DWORD_LOAD(pce, entry)
+#define PCE_STORE(cache, pce, entry) JS_ATOMIC_DWORD_STORE(pce, entry)
+
+#else /* !HAVE_ATOMIC_DWORD_ACCESS */
+
+#define JS_PROPERTY_CACHE_METERING 1
+
+#define PCE_LOAD(cache, pce, entry) \
+ JS_BEGIN_MACRO \
+ uint32 prefills_; \
+ uint32 fills_ = (cache)->fills; \
+ do { \
+ /* Load until cache->fills is stable (see FILL macro below). */ \
+ prefills_ = fills_; \
+ (entry) = *(pce); \
+ } while ((fills_ = (cache)->fills) != prefills_); \
+ JS_END_MACRO
+
+#define PCE_STORE(cache, pce, entry) \
+ JS_BEGIN_MACRO \
+ do { \
+ /* Store until no racing collider stores half or all of pce. */ \
+ *(pce) = (entry); \
+ } while (PCE_OBJECT(*pce) != PCE_OBJECT(entry) || \
+ PCE_PROPERTY(*pce) != PCE_PROPERTY(entry)); \
+ JS_END_MACRO
+
+#endif /* !HAVE_ATOMIC_DWORD_ACCESS */
+
+#else /* !JS_THREADSAFE */
+
+#define PCE_LOAD(cache, pce, entry) ((entry) = *(pce))
+#define PCE_STORE(cache, pce, entry) (*(pce) = (entry))
+
+#endif /* !JS_THREADSAFE */
+
+typedef union JSPropertyCacheEntry {
+ struct {
+ JSObject *object; /* weak link to object */
+ JSScopeProperty *property; /* weak link to property */
+ } s;
+#ifdef HAVE_ATOMIC_DWORD_ACCESS
+ prdword align;
+#endif
+} JSPropertyCacheEntry;
+
+/* These may be called in lvalue or rvalue position. */
+#define PCE_OBJECT(entry) ((entry).s.object)
+#define PCE_PROPERTY(entry) ((entry).s.property)
+
+typedef struct JSPropertyCache {
+ JSPropertyCacheEntry table[PROPERTY_CACHE_SIZE];
+ JSBool empty;
+ JSBool disabled;
+#ifdef JS_PROPERTY_CACHE_METERING
+ uint32 fills;
+ uint32 recycles;
+ uint32 tests;
+ uint32 misses;
+ uint32 flushes;
+# define PCMETER(x) x
+#else
+# define PCMETER(x) /* nothing */
+#endif
+} JSPropertyCache;
+
+#define PROPERTY_CACHE_FILL(cache, obj, id, sprop) \
+ JS_BEGIN_MACRO \
+ JSPropertyCache *cache_ = (cache); \
+ if (!cache_->disabled) { \
+ uintN hashIndex_ = (uintN) PROPERTY_CACHE_HASH(obj, id); \
+ JSPropertyCacheEntry *pce_ = &cache_->table[hashIndex_]; \
+ JSPropertyCacheEntry entry_; \
+ JSScopeProperty *pce_sprop_; \
+ PCE_LOAD(cache_, pce_, entry_); \
+ pce_sprop_ = PCE_PROPERTY(entry_); \
+ PCMETER(if (pce_sprop_ && pce_sprop_ != sprop) \
+ cache_->recycles++); \
+ PCE_OBJECT(entry_) = obj; \
+ PCE_PROPERTY(entry_) = sprop; \
+ cache_->empty = JS_FALSE; \
+ PCMETER(cache_->fills++); \
+ PCE_STORE(cache_, pce_, entry_); \
+ } \
+ JS_END_MACRO
+
+#define PROPERTY_CACHE_TEST(cache, obj, id, sprop) \
+ JS_BEGIN_MACRO \
+ uintN hashIndex_ = (uintN) PROPERTY_CACHE_HASH(obj, id); \
+ JSPropertyCache *cache_ = (cache); \
+ JSPropertyCacheEntry *pce_ = &cache_->table[hashIndex_]; \
+ JSPropertyCacheEntry entry_; \
+ JSScopeProperty *pce_sprop_; \
+ PCE_LOAD(cache_, pce_, entry_); \
+ pce_sprop_ = PCE_PROPERTY(entry_); \
+ PCMETER(cache_->tests++); \
+ if (pce_sprop_ && \
+ PCE_OBJECT(entry_) == obj && \
+ pce_sprop_->id == id) { \
+ sprop = pce_sprop_; \
+ } else { \
+ PCMETER(cache_->misses++); \
+ sprop = NULL; \
+ } \
+ JS_END_MACRO
+
+extern void
+js_FlushPropertyCache(JSContext *cx);
+
+extern void
+js_DisablePropertyCache(JSContext *cx);
+
+extern void
+js_EnablePropertyCache(JSContext *cx);
+
+extern JS_FRIEND_API(jsval *)
+js_AllocStack(JSContext *cx, uintN nslots, void **markp);
+
+extern JS_FRIEND_API(void)
+js_FreeStack(JSContext *cx, void *mark);
+
+extern JSBool
+js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+extern JSBool
+js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+extern JSBool
+js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+extern JSBool
+js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+/*
+ * NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp
+ * is non-null).
+ */
+extern JS_FRIEND_API(JSBool)
+js_Invoke(JSContext *cx, uintN argc, uintN flags);
+
+/*
+ * Consolidated js_Invoke flags simply rename the low JSFRAME_* flags.
+ */
+#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING
+#define JSINVOKE_INTERNAL JSFRAME_INTERNAL
+#define JSINVOKE_SKIP_CALLER JSFRAME_SKIP_CALLER
+
+/*
+ * "Internal" calls may come from C or C++ code using a JSContext on which no
+ * JS is running (!cx->fp), so they may need to push a dummy JSStackFrame.
+ */
+#define js_InternalCall(cx,obj,fval,argc,argv,rval) \
+ js_InternalInvoke(cx, obj, fval, 0, argc, argv, rval)
+
+#define js_InternalConstruct(cx,obj,fval,argc,argv,rval) \
+ js_InternalInvoke(cx, obj, fval, JSINVOKE_CONSTRUCT, argc, argv, rval)
+
+extern JSBool
+js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
+ uintN argc, jsval *argv, jsval *rval);
+
+extern JSBool
+js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
+ JSAccessMode mode, uintN argc, jsval *argv, jsval *rval);
+
+extern JSBool
+js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
+ JSStackFrame *down, uintN flags, jsval *result);
+
+extern JSBool
+js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
+ JSBool *foundp);
+
+extern JSBool
+js_Interpret(JSContext *cx, jsval *result);
+
+JS_END_EXTERN_C
+
+#endif /* jsinterp_h___ */
diff --git a/src/dom/js/jslibmath.h b/src/dom/js/jslibmath.h
new file mode 100644
index 000000000..7cbcf767a
--- /dev/null
+++ b/src/dom/js/jslibmath.h
@@ -0,0 +1,290 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * IBM Corp.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * By default all math calls go to fdlibm. The defines for each platform
+ * remap the math calls to native routines.
+ */
+
+#ifndef _LIBMATH_H
+#define _LIBMATH_H
+
+#include <math.h>
+#include "jsconfig.h"
+
+/*
+ * Define which platforms on which to use fdlibm. Not used
+ * by default since there can be problems with endian-ness and such.
+ */
+
+#if defined(_WIN32) && !defined(__MWERKS__)
+#define JS_USE_FDLIBM_MATH 1
+
+#elif defined(SUNOS4)
+#define JS_USE_FDLIBM_MATH 1
+
+#elif defined(IRIX)
+#define JS_USE_FDLIBM_MATH 1
+
+#elif defined(SOLARIS)
+#define JS_USE_FDLIBM_MATH 1
+
+#elif defined(HPUX)
+#define JS_USE_FDLIBM_MATH 1
+
+#elif defined(linux)
+#define JS_USE_FDLIBM_MATH 1
+
+#elif defined(OSF1)
+/* Want to use some fdlibm functions but fdlibm broken on OSF1/alpha. */
+#define JS_USE_FDLIBM_MATH 0
+
+#elif defined(AIX)
+#define JS_USE_FDLIBM_MATH 1
+
+#else
+#define JS_USE_FDLIBM_MATH 0
+#endif
+
+#if !JS_USE_FDLIBM_MATH
+
+/*
+ * Use system provided math routines.
+ */
+
+#define fd_acos acos
+#define fd_asin asin
+#define fd_atan atan
+#define fd_atan2 atan2
+#define fd_ceil ceil
+#define fd_copysign copysign
+#define fd_cos cos
+#define fd_exp exp
+#define fd_fabs fabs
+#define fd_floor floor
+#define fd_fmod fmod
+#define fd_log log
+#define fd_pow pow
+#define fd_sin sin
+#define fd_sqrt sqrt
+#define fd_tan tan
+
+#else
+
+/*
+ * Use math routines in fdlibm.
+ */
+
+#undef __P
+#ifdef __STDC__
+#define __P(p) p
+#else
+#define __P(p) ()
+#endif
+
+#if defined _WIN32 || defined SUNOS4
+
+#define fd_acos acos
+#define fd_asin asin
+#define fd_atan atan
+#define fd_cos cos
+#define fd_sin sin
+#define fd_tan tan
+#define fd_exp exp
+#define fd_log log
+#define fd_sqrt sqrt
+#define fd_ceil ceil
+#define fd_fabs fabs
+#define fd_floor floor
+#define fd_fmod fmod
+
+extern double fd_atan2 __P((double, double));
+extern double fd_copysign __P((double, double));
+extern double fd_pow __P((double, double));
+
+#elif defined IRIX
+
+#define fd_acos acos
+#define fd_asin asin
+#define fd_atan atan
+#define fd_exp exp
+#define fd_log log
+#define fd_log10 log10
+#define fd_sqrt sqrt
+#define fd_fabs fabs
+#define fd_floor floor
+#define fd_fmod fmod
+
+extern double fd_cos __P((double));
+extern double fd_sin __P((double));
+extern double fd_tan __P((double));
+extern double fd_atan2 __P((double, double));
+extern double fd_pow __P((double, double));
+extern double fd_ceil __P((double));
+extern double fd_copysign __P((double, double));
+
+#elif defined SOLARIS
+
+#define fd_atan atan
+#define fd_cos cos
+#define fd_sin sin
+#define fd_tan tan
+#define fd_exp exp
+#define fd_sqrt sqrt
+#define fd_ceil ceil
+#define fd_fabs fabs
+#define fd_floor floor
+#define fd_fmod fmod
+
+extern double fd_acos __P((double));
+extern double fd_asin __P((double));
+extern double fd_log __P((double));
+extern double fd_atan2 __P((double, double));
+extern double fd_pow __P((double, double));
+extern double fd_copysign __P((double, double));
+
+#elif defined HPUX
+
+#define fd_cos cos
+#define fd_sin sin
+#define fd_exp exp
+#define fd_sqrt sqrt
+#define fd_fabs fabs
+#define fd_floor floor
+#define fd_fmod fmod
+
+extern double fd_ceil __P((double));
+extern double fd_acos __P((double));
+extern double fd_log __P((double));
+extern double fd_atan2 __P((double, double));
+extern double fd_tan __P((double));
+extern double fd_pow __P((double, double));
+extern double fd_asin __P((double));
+extern double fd_atan __P((double));
+extern double fd_copysign __P((double, double));
+
+#elif defined(linux)
+
+#define fd_atan atan
+#define fd_atan2 atan2
+#define fd_ceil ceil
+#define fd_cos cos
+#define fd_fabs fabs
+#define fd_floor floor
+#define fd_fmod fmod
+#define fd_sin sin
+#define fd_sqrt sqrt
+#define fd_tan tan
+#define fd_copysign copysign
+
+extern double fd_asin __P((double));
+extern double fd_acos __P((double));
+extern double fd_exp __P((double));
+extern double fd_log __P((double));
+extern double fd_pow __P((double, double));
+
+#elif defined(OSF1)
+
+#define fd_acos acos
+#define fd_asin asin
+#define fd_atan atan
+#define fd_copysign copysign
+#define fd_cos cos
+#define fd_exp exp
+#define fd_fabs fabs
+#define fd_fmod fmod
+#define fd_sin sin
+#define fd_sqrt sqrt
+#define fd_tan tan
+
+extern double fd_atan2 __P((double, double));
+extern double fd_ceil __P((double));
+extern double fd_floor __P((double));
+extern double fd_log __P((double));
+extern double fd_pow __P((double, double));
+
+#elif defined(AIX)
+
+#define fd_acos acos
+#define fd_asin asin
+#define fd_atan2 atan2
+#define fd_copysign copysign
+#define fd_cos cos
+#define fd_exp exp
+#define fd_fabs fabs
+#define fd_floor floor
+#define fd_fmod fmod
+#define fd_log log
+#define fd_sin sin
+#define fd_sqrt sqrt
+
+extern double fd_atan __P((double));
+extern double fd_ceil __P((double));
+extern double fd_pow __P((double,double));
+extern double fd_tan __P((double));
+
+#else /* other platform.. generic paranoid slow fdlibm */
+
+extern double fd_acos __P((double));
+extern double fd_asin __P((double));
+extern double fd_atan __P((double));
+extern double fd_cos __P((double));
+extern double fd_sin __P((double));
+extern double fd_tan __P((double));
+
+extern double fd_exp __P((double));
+extern double fd_log __P((double));
+extern double fd_sqrt __P((double));
+
+extern double fd_ceil __P((double));
+extern double fd_fabs __P((double));
+extern double fd_floor __P((double));
+extern double fd_fmod __P((double, double));
+
+extern double fd_atan2 __P((double, double));
+extern double fd_pow __P((double, double));
+extern double fd_copysign __P((double, double));
+
+#endif
+
+#endif /* JS_USE_FDLIBM_MATH */
+
+#endif /* _LIBMATH_H */
+
diff --git a/src/dom/js/jslock.c b/src/dom/js/jslock.c
new file mode 100644
index 000000000..9709c8cc0
--- /dev/null
+++ b/src/dom/js/jslock.c
@@ -0,0 +1,1241 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef JS_THREADSAFE
+
+/*
+ * JS locking stubs.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include "jspubtd.h"
+#include "prthread.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jstypes.h"
+#include "jsbit.h"
+#include "jscntxt.h"
+#include "jsdtoa.h"
+#include "jsgc.h"
+#include "jslock.h"
+#include "jsscope.h"
+#include "jsstr.h"
+
+#define ReadWord(W) (W)
+
+#ifndef NSPR_LOCK
+
+#include <memory.h>
+
+static PRLock **global_locks;
+static uint32 global_lock_count = 1;
+static uint32 global_locks_log2 = 0;
+static uint32 global_locks_mask = 0;
+
+#define GLOBAL_LOCK_INDEX(id) (((uint32)(id) >> 2) & global_locks_mask)
+
+static void
+js_LockGlobal(void *id)
+{
+ uint32 i = GLOBAL_LOCK_INDEX(id);
+ PR_Lock(global_locks[i]);
+}
+
+static void
+js_UnlockGlobal(void *id)
+{
+ uint32 i = GLOBAL_LOCK_INDEX(id);
+ PR_Unlock(global_locks[i]);
+}
+
+/* Exclude Alpha NT. */
+#if defined(_WIN32) && defined(_M_IX86)
+#pragma warning( disable : 4035 )
+
+static JS_INLINE int
+js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
+{
+ __asm {
+ mov eax, ov
+ mov ecx, nv
+ mov ebx, w
+ lock cmpxchg [ebx], ecx
+ sete al
+ and eax, 1h
+ }
+}
+
+#elif defined(__GNUC__) && defined(__i386__)
+
+/* Note: This fails on 386 cpus, cmpxchgl is a >= 486 instruction */
+static JS_INLINE int
+js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
+{
+ unsigned int res;
+
+ __asm__ __volatile__ (
+ "lock\n"
+ "cmpxchgl %2, (%1)\n"
+ "sete %%al\n"
+ "andl $1, %%eax\n"
+ : "=a" (res)
+ : "r" (w), "r" (nv), "a" (ov)
+ : "cc", "memory");
+ return (int)res;
+}
+
+#elif defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)
+
+static JS_INLINE int
+js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
+{
+#if defined(__GNUC__)
+ unsigned int res;
+ JS_ASSERT(ov != nv);
+ asm volatile ("\
+stbar\n\
+cas [%1],%2,%3\n\
+cmp %2,%3\n\
+be,a 1f\n\
+mov 1,%0\n\
+mov 0,%0\n\
+1:"
+ : "=r" (res)
+ : "r" (w), "r" (ov), "r" (nv));
+ return (int)res;
+#else /* !__GNUC__ */
+ extern int compare_and_swap(jsword*, jsword, jsword);
+ JS_ASSERT(ov != nv);
+ return compare_and_swap(w, ov, nv);
+#endif
+}
+
+#elif defined(AIX)
+
+#include <sys/atomic_op.h>
+
+static JS_INLINE int
+js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
+{
+ return !_check_lock((atomic_p)w, ov, nv);
+}
+
+#else
+
+#error "Define NSPR_LOCK if your platform lacks a compare-and-swap instruction."
+
+#endif /* arch-tests */
+
+#endif /* !NSPR_LOCK */
+
+jsword
+js_CurrentThreadId()
+{
+ return CurrentThreadId();
+}
+
+void
+js_InitLock(JSThinLock *tl)
+{
+#ifdef NSPR_LOCK
+ tl->owner = 0;
+ tl->fat = (JSFatLock*)JS_NEW_LOCK();
+#else
+ memset(tl, 0, sizeof(JSThinLock));
+#endif
+}
+
+void
+js_FinishLock(JSThinLock *tl)
+{
+#ifdef NSPR_LOCK
+ tl->owner = 0xdeadbeef;
+ if (tl->fat)
+ JS_DESTROY_LOCK(((JSLock*)tl->fat));
+#else
+ JS_ASSERT(tl->owner == 0);
+ JS_ASSERT(tl->fat == NULL);
+#endif
+}
+
+static void js_Dequeue(JSThinLock *);
+
+#ifdef DEBUG_SCOPE_COUNT
+
+#include <stdio.h>
+#include "jsdhash.h"
+
+static FILE *logfp;
+static JSDHashTable logtbl;
+
+typedef struct logentry {
+ JSDHashEntryStub stub;
+ char op;
+ const char *file;
+ int line;
+} logentry;
+
+static void
+logit(JSScope *scope, char op, const char *file, int line)
+{
+ logentry *entry;
+
+ if (!logfp) {
+ logfp = fopen("/tmp/scope.log", "w");
+ if (!logfp)
+ return;
+ setvbuf(logfp, NULL, _IONBF, 0);
+ }
+ fprintf(logfp, "%p %c %s %d\n", scope, op, file, line);
+
+ if (!logtbl.entryStore &&
+ !JS_DHashTableInit(&logtbl, JS_DHashGetStubOps(), NULL,
+ sizeof(logentry), 100)) {
+ return;
+ }
+ entry = (logentry *) JS_DHashTableOperate(&logtbl, scope, JS_DHASH_ADD);
+ if (!entry)
+ return;
+ entry->stub.key = scope;
+ entry->op = op;
+ entry->file = file;
+ entry->line = line;
+}
+
+void
+js_unlog_scope(JSScope *scope)
+{
+ if (!logtbl.entryStore)
+ return;
+ (void) JS_DHashTableOperate(&logtbl, scope, JS_DHASH_REMOVE);
+}
+
+# define LOGIT(scope,op) logit(scope, op, __FILE__, __LINE__)
+
+#else
+
+# define LOGIT(scope,op) /* nothing */
+
+#endif /* DEBUG_SCOPE_COUNT */
+
+/*
+ * Return true if scope's ownercx, or the ownercx of a single-threaded scope
+ * for which ownercx is waiting to become multi-threaded and shared, is cx.
+ * That condition implies deadlock in ClaimScope if cx's thread were to wait
+ * to share scope.
+ *
+ * (i) rt->gcLock held
+ */
+static JSBool
+WillDeadlock(JSScope *scope, JSContext *cx)
+{
+ JSContext *ownercx;
+
+ do {
+ ownercx = scope->ownercx;
+ if (ownercx == cx) {
+ JS_RUNTIME_METER(cx->runtime, deadlocksAvoided);
+ return JS_TRUE;
+ }
+ } while (ownercx && (scope = ownercx->scopeToShare) != NULL);
+ return JS_FALSE;
+}
+
+/*
+ * Make scope multi-threaded, i.e. share its ownership among contexts in rt
+ * using a "thin" or (if necessary due to contention) "fat" lock. Called only
+ * from ClaimScope, immediately below, when we detect deadlock were we to wait
+ * for scope's lock, because its ownercx is waiting on a scope owned by the
+ * calling cx.
+ *
+ * (i) rt->gcLock held
+ */
+static void
+ShareScope(JSRuntime *rt, JSScope *scope)
+{
+ JSScope **todop;
+
+ if (scope->u.link) {
+ for (todop = &rt->scopeSharingTodo; *todop != scope;
+ todop = &(*todop)->u.link) {
+ JS_ASSERT(*todop != NO_SCOPE_SHARING_TODO);
+ }
+ *todop = scope->u.link;
+ scope->u.link = NULL; /* null u.link for sanity ASAP */
+ JS_NOTIFY_ALL_CONDVAR(rt->scopeSharingDone);
+ }
+ js_InitLock(&scope->lock);
+ if (scope == rt->setSlotScope) {
+ /*
+ * Nesting locks on another thread that's using scope->ownercx: give
+ * the held lock a reentrancy count of 1 and set its lock.owner field
+ * directly (no compare-and-swap needed while scope->ownercx is still
+ * non-null). See below in ClaimScope, before the ShareScope call,
+ * for more on why this is necessary.
+ *
+ * If NSPR_LOCK is defined, we cannot deadlock holding rt->gcLock and
+ * acquiring scope->lock.fat here, against another thread holding that
+ * fat lock and trying to grab rt->gcLock. This is because no other
+ * thread can attempt to acquire scope->lock.fat until scope->ownercx
+ * is null *and* our thread has released rt->gcLock, which interlocks
+ * scope->ownercx's transition to null against tests of that member
+ * in ClaimScope.
+ */
+ scope->lock.owner = scope->ownercx->thread;
+#ifdef NSPR_LOCK
+ JS_ACQUIRE_LOCK((JSLock*)scope->lock.fat);
+#endif
+ scope->u.count = 1;
+ } else {
+ scope->u.count = 0;
+ }
+ js_FinishSharingScope(rt, scope);
+}
+
+/*
+ * js_FinishSharingScope is the tail part of ShareScope, split out to become a
+ * subroutine of JS_EndRequest too. The bulk of the work here involves making
+ * mutable strings in the scope's object's slots be immutable. We have to do
+ * this because such strings will soon be available to multiple threads, so
+ * their buffers can't be realloc'd any longer in js_ConcatStrings, and their
+ * members can't be modified by js_ConcatStrings, js_MinimizeDependentStrings,
+ * or js_UndependString.
+ *
+ * The last bit of work done by js_FinishSharingScope nulls scope->ownercx and
+ * updates rt->sharedScopes.
+ */
+#define MAKE_STRING_IMMUTABLE(rt, v, vp) \
+ JS_BEGIN_MACRO \
+ JSString *str_ = JSVAL_TO_STRING(v); \
+ uint8 *flagp_ = js_GetGCThingFlags(str_); \
+ if (*flagp_ & GCF_MUTABLE) { \
+ if (JSSTRING_IS_DEPENDENT(str_) && \
+ !js_UndependString(NULL, str_)) { \
+ JS_RUNTIME_METER(rt, badUndependStrings); \
+ *vp = JSVAL_VOID; \
+ } else { \
+ *flagp_ &= ~GCF_MUTABLE; \
+ } \
+ } \
+ JS_END_MACRO
+
+void
+js_FinishSharingScope(JSRuntime *rt, JSScope *scope)
+{
+ JSObject *obj;
+ uint32 nslots;
+ jsval v, *vp, *end;
+
+ obj = scope->object;
+ nslots = JS_MIN(obj->map->freeslot, obj->map->nslots);
+ for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
+ v = *vp;
+ if (JSVAL_IS_STRING(v))
+ MAKE_STRING_IMMUTABLE(rt, v, vp);
+ }
+
+ scope->ownercx = NULL; /* NB: set last, after lock init */
+ JS_RUNTIME_METER(rt, sharedScopes);
+}
+
+/*
+ * Given a scope with apparently non-null ownercx different from cx, try to
+ * set ownercx to cx, claiming exclusive (single-threaded) ownership of scope.
+ * If we claim ownership, return true. Otherwise, we wait for ownercx to be
+ * set to null (indicating that scope is multi-threaded); or if waiting would
+ * deadlock, we set ownercx to null ourselves via ShareScope. In any case,
+ * once ownercx is null we return false.
+ */
+static JSBool
+ClaimScope(JSScope *scope, JSContext *cx)
+{
+ JSRuntime *rt;
+ JSContext *ownercx;
+ jsrefcount saveDepth;
+ PRStatus stat;
+
+ rt = cx->runtime;
+ JS_RUNTIME_METER(rt, claimAttempts);
+ JS_LOCK_GC(rt);
+
+ /* Reload in case ownercx went away while we blocked on the lock. */
+ while ((ownercx = scope->ownercx) != NULL) {
+ /*
+ * Avoid selflock if ownercx is dead, or is not running a request, or
+ * has the same thread as cx. Set scope->ownercx to cx so that the
+ * matching JS_UNLOCK_SCOPE or JS_UNLOCK_OBJ macro call will take the
+ * fast path around the corresponding js_UnlockScope or js_UnlockObj
+ * function call.
+ *
+ * If scope->u.link is non-null, scope has already been inserted on
+ * the rt->scopeSharingTodo list, because another thread's context
+ * already wanted to lock scope while ownercx was running a request.
+ * We can't claim any scope whose u.link is non-null at this point,
+ * even if ownercx->requestDepth is 0 (see below where we suspend our
+ * request before waiting on rt->scopeSharingDone).
+ */
+ if (!scope->u.link &&
+ (!js_ValidContextPointer(rt, ownercx) ||
+ !ownercx->requestDepth ||
+ ownercx->thread == cx->thread)) {
+ JS_ASSERT(scope->u.count == 0);
+ scope->ownercx = cx;
+ JS_UNLOCK_GC(rt);
+ JS_RUNTIME_METER(rt, claimedScopes);
+ return JS_TRUE;
+ }
+
+ /*
+ * Avoid deadlock if scope's owner context is waiting on a scope that
+ * we own, by revoking scope's ownership. This approach to deadlock
+ * avoidance works because the engine never nests scope locks, except
+ * for the notable case of js_SetProtoOrParent (see jsobj.c).
+ *
+ * If cx could hold locks on ownercx->scopeToShare, or if ownercx
+ * could hold locks on scope, we would need to keep reentrancy counts
+ * for all such "flyweight" (ownercx != NULL) locks, so that control
+ * would unwind properly once these locks became "thin" or "fat".
+ * Apart from the js_SetProtoOrParent exception, the engine promotes
+ * a scope from exclusive to shared access only when locking, never
+ * when holding or unlocking.
+ *
+ * If ownercx's thread is calling js_SetProtoOrParent, trying to lock
+ * the inner scope (the scope of the object being set as the prototype
+ * of the outer object), ShareScope will find the outer object's scope
+ * at rt->setSlotScope. If it's the same as scope, we give it a lock
+ * held by ownercx's thread with reentrancy count of 1, then we return
+ * here and break. After that we unwind to js_[GS]etSlotThreadSafe or
+ * js_LockScope (our caller), where we wait on the newly-fattened lock
+ * until ownercx's thread unwinds from js_SetProtoOrParent.
+ *
+ * Avoid deadlock before any of this scope/context cycle detection if
+ * cx is on the active GC's thread, because in that case, no requests
+ * will run until the GC completes. Any scope wanted by the GC (from
+ * a finalizer) that can't be claimed must be slated for sharing.
+ */
+ if (rt->gcThread == cx->thread ||
+ (ownercx->scopeToShare &&
+ WillDeadlock(ownercx->scopeToShare, cx))) {
+ ShareScope(rt, scope);
+ break;
+ }
+
+ /*
+ * Thanks to the non-zero NO_SCOPE_SHARING_TODO link terminator, we
+ * can decide whether scope is on rt->scopeSharingTodo with a single
+ * non-null test, and avoid double-insertion bugs.
+ */
+ if (!scope->u.link) {
+ scope->u.link = rt->scopeSharingTodo;
+ rt->scopeSharingTodo = scope;
+ js_HoldObjectMap(cx, &scope->map);
+ }
+
+ /*
+ * Inline JS_SuspendRequest before we wait on rt->scopeSharingDone,
+ * saving and clearing cx->requestDepth so we don't deadlock if the
+ * GC needs to run on ownercx.
+ *
+ * Unlike JS_SuspendRequest and JS_EndRequest, we must take care not
+ * to decrement rt->requestCount if cx is active on the GC's thread,
+ * because the GC has already reduced rt->requestCount to exclude all
+ * such such contexts.
+ */
+ saveDepth = cx->requestDepth;
+ if (saveDepth) {
+ cx->requestDepth = 0;
+ if (rt->gcThread != cx->thread) {
+ JS_ASSERT(rt->requestCount > 0);
+ rt->requestCount--;
+ if (rt->requestCount == 0)
+ JS_NOTIFY_REQUEST_DONE(rt);
+ }
+ }
+
+ /*
+ * We know that some other thread's context owns scope, which is now
+ * linked onto rt->scopeSharingTodo, awaiting the end of that other
+ * thread's request. So it is safe to wait on rt->scopeSharingDone.
+ */
+ cx->scopeToShare = scope;
+ stat = PR_WaitCondVar(rt->scopeSharingDone, PR_INTERVAL_NO_TIMEOUT);
+ JS_ASSERT(stat != PR_FAILURE);
+
+ /*
+ * Inline JS_ResumeRequest after waiting on rt->scopeSharingDone,
+ * restoring cx->requestDepth. Same note as above for the inlined,
+ * specialized JS_SuspendRequest code: beware rt->gcThread.
+ */
+ if (saveDepth) {
+ if (rt->gcThread != cx->thread) {
+ while (rt->gcLevel > 0)
+ JS_AWAIT_GC_DONE(rt);
+ rt->requestCount++;
+ }
+ cx->requestDepth = saveDepth;
+ }
+
+ /*
+ * Don't clear cx->scopeToShare until after we're through waiting on
+ * all condition variables protected by rt->gcLock -- that includes
+ * rt->scopeSharingDone *and* rt->gcDone (hidden in JS_AWAIT_GC_DONE,
+ * in the inlined JS_ResumeRequest code immediately above).
+ *
+ * Otherwise, the GC could easily deadlock with another thread that
+ * owns a scope wanted by a finalizer. By keeping cx->scopeToShare
+ * set till here, we ensure that such deadlocks are detected, which
+ * results in the finalized object's scope being shared (it must, of
+ * course, have other, live objects sharing it).
+ */
+ cx->scopeToShare = NULL;
+ }
+
+ JS_UNLOCK_GC(rt);
+ return JS_FALSE;
+}
+
+/* Exported to js.c, which calls it via OBJ_GET_* and JSVAL_IS_* macros. */
+JS_FRIEND_API(jsval)
+js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
+{
+ jsval v;
+ JSScope *scope;
+#ifndef NSPR_LOCK
+ JSThinLock *tl;
+ jsword me;
+#endif
+
+ /*
+ * We handle non-native objects via JSObjectOps.getRequiredSlot, treating
+ * all slots starting from 0 as required slots. A property definition or
+ * some prior arrangement must have allocated slot.
+ *
+ * Note once again (see jspubtd.h, before JSGetRequiredSlotOp's typedef)
+ * the crucial distinction between a |required slot number| that's passed
+ * to the get/setRequiredSlot JSObjectOps, and a |reserved slot index|
+ * passed to the JS_Get/SetReservedSlot APIs.
+ */
+ if (!OBJ_IS_NATIVE(obj))
+ return OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
+
+ /*
+ * Native object locking is inlined here to optimize the single-threaded
+ * and contention-free multi-threaded cases.
+ */
+ scope = OBJ_SCOPE(obj);
+ JS_ASSERT(scope->ownercx != cx);
+ JS_ASSERT(obj->slots && slot < obj->map->freeslot);
+
+ /*
+ * Avoid locking if called from the GC (see GC_AWARE_GET_SLOT in jsobj.h).
+ * Also avoid locking an object owning a sealed scope. If neither of those
+ * special cases applies, try to claim scope's flyweight lock from whatever
+ * context may have had it in an earlier request.
+ */
+ if (CX_THREAD_IS_RUNNING_GC(cx) ||
+ (SCOPE_IS_SEALED(scope) && scope->object == obj) ||
+ (scope->ownercx && ClaimScope(scope, cx))) {
+ return obj->slots[slot];
+ }
+
+#ifndef NSPR_LOCK
+ tl = &scope->lock;
+ me = cx->thread;
+ JS_ASSERT(me == CurrentThreadId());
+ if (js_CompareAndSwap(&tl->owner, 0, me)) {
+ /*
+ * Got the lock with one compare-and-swap. Even so, someone else may
+ * have mutated obj so it now has its own scope and lock, which would
+ * require either a restart from the top of this routine, or a thin
+ * lock release followed by fat lock acquisition.
+ */
+ if (scope == OBJ_SCOPE(obj)) {
+ v = obj->slots[slot];
+ if (!js_CompareAndSwap(&tl->owner, me, 0)) {
+ /* Assert that scope locks never revert to flyweight. */
+ JS_ASSERT(scope->ownercx != cx);
+ LOGIT(scope, '1');
+ scope->u.count = 1;
+ js_UnlockObj(cx, obj);
+ }
+ return v;
+ }
+ if (!js_CompareAndSwap(&tl->owner, me, 0))
+ js_Dequeue(tl);
+ }
+ else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
+ return obj->slots[slot];
+ }
+#endif
+
+ js_LockObj(cx, obj);
+ v = obj->slots[slot];
+
+ /*
+ * Test whether cx took ownership of obj's scope during js_LockObj.
+ *
+ * This does not mean that a given scope reverted to flyweight from "thin"
+ * or "fat" -- it does mean that obj's map pointer changed due to another
+ * thread setting a property, requiring obj to cease sharing a prototype
+ * object's scope (whose lock was not flyweight, else we wouldn't be here
+ * in the first place!).
+ */
+ scope = OBJ_SCOPE(obj);
+ if (scope->ownercx != cx)
+ js_UnlockScope(cx, scope);
+ return v;
+}
+
+void
+js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
+{
+ JSScope *scope;
+#ifndef NSPR_LOCK
+ JSThinLock *tl;
+ jsword me;
+#endif
+
+ /* Any string stored in a thread-safe object must be immutable. */
+ if (JSVAL_IS_STRING(v))
+ MAKE_STRING_IMMUTABLE(cx->runtime, v, &v);
+
+ /*
+ * We handle non-native objects via JSObjectOps.setRequiredSlot, as above
+ * for the Get case.
+ */
+ if (!OBJ_IS_NATIVE(obj)) {
+ OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
+ return;
+ }
+
+ /*
+ * Native object locking is inlined here to optimize the single-threaded
+ * and contention-free multi-threaded cases.
+ */
+ scope = OBJ_SCOPE(obj);
+ JS_ASSERT(scope->ownercx != cx);
+ JS_ASSERT(obj->slots && slot < obj->map->freeslot);
+
+ /*
+ * Avoid locking if called from the GC (see GC_AWARE_GET_SLOT in jsobj.h).
+ * Also avoid locking an object owning a sealed scope. If neither of those
+ * special cases applies, try to claim scope's flyweight lock from whatever
+ * context may have had it in an earlier request.
+ */
+ if (CX_THREAD_IS_RUNNING_GC(cx) ||
+ (SCOPE_IS_SEALED(scope) && scope->object == obj) ||
+ (scope->ownercx && ClaimScope(scope, cx))) {
+ obj->slots[slot] = v;
+ return;
+ }
+
+#ifndef NSPR_LOCK
+ tl = &scope->lock;
+ me = cx->thread;
+ JS_ASSERT(me == CurrentThreadId());
+ if (js_CompareAndSwap(&tl->owner, 0, me)) {
+ if (scope == OBJ_SCOPE(obj)) {
+ obj->slots[slot] = v;
+ if (!js_CompareAndSwap(&tl->owner, me, 0)) {
+ /* Assert that scope locks never revert to flyweight. */
+ JS_ASSERT(scope->ownercx != cx);
+ LOGIT(scope, '1');
+ scope->u.count = 1;
+ js_UnlockObj(cx, obj);
+ }
+ return;
+ }
+ if (!js_CompareAndSwap(&tl->owner, me, 0))
+ js_Dequeue(tl);
+ }
+ else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
+ obj->slots[slot] = v;
+ return;
+ }
+#endif
+
+ js_LockObj(cx, obj);
+ obj->slots[slot] = v;
+
+ /*
+ * Same drill as above, in js_GetSlotThreadSafe. Note that we cannot
+ * assume obj has its own mutable scope (where scope->object == obj) yet,
+ * because OBJ_SET_SLOT is called for the "universal", common slots such
+ * as JSSLOT_PROTO and JSSLOT_PARENT, without a prior js_GetMutableScope.
+ * See also the JSPROP_SHARED attribute and its usage.
+ */
+ scope = OBJ_SCOPE(obj);
+ if (scope->ownercx != cx)
+ js_UnlockScope(cx, scope);
+}
+
+#ifndef NSPR_LOCK
+
+static JSFatLock *
+NewFatlock()
+{
+ JSFatLock *fl = (JSFatLock *)malloc(sizeof(JSFatLock)); /* for now */
+ if (!fl) return NULL;
+ fl->susp = 0;
+ fl->next = NULL;
+ fl->prevp = NULL;
+ fl->slock = PR_NewLock();
+ fl->svar = PR_NewCondVar(fl->slock);
+ return fl;
+}
+
+static void
+DestroyFatlock(JSFatLock *fl)
+{
+ PR_DestroyLock(fl->slock);
+ PR_DestroyCondVar(fl->svar);
+ free(fl);
+}
+
+static JSFatLock *
+ListOfFatlocks(int listc)
+{
+ JSFatLock *m;
+ JSFatLock *m0;
+ int i;
+
+ JS_ASSERT(listc>0);
+ m0 = m = NewFatlock();
+ for (i=1; i<listc; i++) {
+ m->next = NewFatlock();
+ m = m->next;
+ }
+ return m0;
+}
+
+static void
+DeleteListOfFatlocks(JSFatLock *m)
+{
+ JSFatLock *m0;
+ for (; m; m=m0) {
+ m0 = m->next;
+ DestroyFatlock(m);
+ }
+}
+
+static JSFatLockTable *fl_list_table = NULL;
+static uint32 fl_list_table_len = 0;
+static uint32 fl_list_chunk_len = 0;
+
+static JSFatLock *
+GetFatlock(void *id)
+{
+ JSFatLock *m;
+
+ uint32 i = GLOBAL_LOCK_INDEX(id);
+ if (fl_list_table[i].free == NULL) {
+#ifdef DEBUG
+ if (fl_list_table[i].taken)
+ printf("Ran out of fat locks!\n");
+#endif
+ fl_list_table[i].free = ListOfFatlocks(fl_list_chunk_len);
+ }
+ m = fl_list_table[i].free;
+ fl_list_table[i].free = m->next;
+ m->susp = 0;
+ m->next = fl_list_table[i].taken;
+ m->prevp = &fl_list_table[i].taken;
+ if (fl_list_table[i].taken)
+ fl_list_table[i].taken->prevp = &m->next;
+ fl_list_table[i].taken = m;
+ return m;
+}
+
+static void
+PutFatlock(JSFatLock *m, void *id)
+{
+ uint32 i;
+ if (m == NULL)
+ return;
+
+ /* Unlink m from fl_list_table[i].taken. */
+ *m->prevp = m->next;
+ if (m->next)
+ m->next->prevp = m->prevp;
+
+ /* Insert m in fl_list_table[i].free. */
+ i = GLOBAL_LOCK_INDEX(id);
+ m->next = fl_list_table[i].free;
+ fl_list_table[i].free = m;
+}
+
+#endif /* !NSPR_LOCK */
+
+JSBool
+js_SetupLocks(int listc, int globc)
+{
+#ifndef NSPR_LOCK
+ uint32 i;
+
+ if (global_locks)
+ return JS_TRUE;
+#ifdef DEBUG
+ if (listc > 10000 || listc < 0) /* listc == fat lock list chunk length */
+ printf("Bad number %d in js_SetupLocks()!\n", listc);
+ if (globc > 100 || globc < 0) /* globc == number of global locks */
+ printf("Bad number %d in js_SetupLocks()!\n", listc);
+#endif
+ global_locks_log2 = JS_CeilingLog2(globc);
+ global_locks_mask = JS_BITMASK(global_locks_log2);
+ global_lock_count = JS_BIT(global_locks_log2);
+ global_locks = (PRLock **) malloc(global_lock_count * sizeof(PRLock*));
+ if (!global_locks)
+ return JS_FALSE;
+ for (i = 0; i < global_lock_count; i++) {
+ global_locks[i] = PR_NewLock();
+ if (!global_locks[i]) {
+ global_lock_count = i;
+ js_CleanupLocks();
+ return JS_FALSE;
+ }
+ }
+ fl_list_table = (JSFatLockTable *) malloc(i * sizeof(JSFatLockTable));
+ if (!fl_list_table) {
+ js_CleanupLocks();
+ return JS_FALSE;
+ }
+ fl_list_table_len = global_lock_count;
+ for (i = 0; i < global_lock_count; i++)
+ fl_list_table[i].free = fl_list_table[i].taken = NULL;
+ fl_list_chunk_len = listc;
+#endif /* !NSPR_LOCK */
+ return JS_TRUE;
+}
+
+void
+js_CleanupLocks()
+{
+#ifndef NSPR_LOCK
+ uint32 i;
+
+ if (global_locks) {
+ for (i = 0; i < global_lock_count; i++)
+ PR_DestroyLock(global_locks[i]);
+ free(global_locks);
+ global_locks = NULL;
+ global_lock_count = 1;
+ global_locks_log2 = 0;
+ global_locks_mask = 0;
+ }
+ if (fl_list_table) {
+ for (i = 0; i < fl_list_table_len; i++) {
+ DeleteListOfFatlocks(fl_list_table[i].free);
+ fl_list_table[i].free = NULL;
+ DeleteListOfFatlocks(fl_list_table[i].taken);
+ fl_list_table[i].taken = NULL;
+ }
+ free(fl_list_table);
+ fl_list_table = NULL;
+ fl_list_table_len = 0;
+ }
+#endif /* !NSPR_LOCK */
+}
+
+void
+js_InitContextForLocking(JSContext *cx)
+{
+ cx->thread = CurrentThreadId();
+ JS_ASSERT(Thin_GetWait(cx->thread) == 0);
+}
+
+#ifndef NSPR_LOCK
+
+/*
+ * Fast locking and unlocking is implemented by delaying the allocation of a
+ * system lock (fat lock) until contention. As long as a locking thread A
+ * runs uncontended, the lock is represented solely by storing A's identity in
+ * the object being locked.
+ *
+ * If another thread B tries to lock the object currently locked by A, B is
+ * enqueued into a fat lock structure (which might have to be allocated and
+ * pointed to by the object), and suspended using NSPR conditional variables
+ * (wait). A wait bit (Bacon bit) is set in the lock word of the object,
+ * signalling to A that when releasing the lock, B must be dequeued and
+ * notified.
+ *
+ * The basic operation of the locking primitives (js_Lock, js_Unlock,
+ * js_Enqueue, and js_Dequeue) is compare-and-swap. Hence, when locking into
+ * the word pointed at by p, compare-and-swap(p, 0, A) success implies that p
+ * is unlocked. Similarly, when unlocking p, if compare-and-swap(p, A, 0)
+ * succeeds this implies that p is uncontended (no one is waiting because the
+ * wait bit is not set).
+ *
+ * When dequeueing, the lock is released, and one of the threads suspended on
+ * the lock is notified. If other threads still are waiting, the wait bit is
+ * kept (in js_Enqueue), and if not, the fat lock is deallocated.
+ *
+ * The functions js_Enqueue, js_Dequeue, js_SuspendThread, and js_ResumeThread
+ * are serialized using a global lock. For scalability, a hashtable of global
+ * locks is used, which is indexed modulo the thin lock pointer.
+ */
+
+/*
+ * Invariants:
+ * (i) global lock is held
+ * (ii) fl->susp >= 0
+ */
+static int
+js_SuspendThread(JSThinLock *tl)
+{
+ JSFatLock *fl;
+ PRStatus stat;
+
+ if (tl->fat == NULL)
+ fl = tl->fat = GetFatlock(tl);
+ else
+ fl = tl->fat;
+ JS_ASSERT(fl->susp >= 0);
+ fl->susp++;
+ PR_Lock(fl->slock);
+ js_UnlockGlobal(tl);
+ stat = PR_WaitCondVar(fl->svar, PR_INTERVAL_NO_TIMEOUT);
+ JS_ASSERT(stat != PR_FAILURE);
+ PR_Unlock(fl->slock);
+ js_LockGlobal(tl);
+ fl->susp--;
+ if (fl->susp == 0) {
+ PutFatlock(fl, tl);
+ tl->fat = NULL;
+ }
+ return tl->fat == NULL;
+}
+
+/*
+ * (i) global lock is held
+ * (ii) fl->susp > 0
+ */
+static void
+js_ResumeThread(JSThinLock *tl)
+{
+ JSFatLock *fl = tl->fat;
+ PRStatus stat;
+
+ JS_ASSERT(fl != NULL);
+ JS_ASSERT(fl->susp > 0);
+ PR_Lock(fl->slock);
+ js_UnlockGlobal(tl);
+ stat = PR_NotifyCondVar(fl->svar);
+ JS_ASSERT(stat != PR_FAILURE);
+ PR_Unlock(fl->slock);
+}
+
+static void
+js_Enqueue(JSThinLock *tl, jsword me)
+{
+ jsword o, n;
+
+ js_LockGlobal(tl);
+ for (;;) {
+ o = ReadWord(tl->owner);
+ n = Thin_SetWait(o);
+ if (o != 0 && js_CompareAndSwap(&tl->owner, o, n)) {
+ if (js_SuspendThread(tl))
+ me = Thin_RemoveWait(me);
+ else
+ me = Thin_SetWait(me);
+ }
+ else if (js_CompareAndSwap(&tl->owner, 0, me)) {
+ js_UnlockGlobal(tl);
+ return;
+ }
+ }
+}
+
+static void
+js_Dequeue(JSThinLock *tl)
+{
+ jsword o;
+
+ js_LockGlobal(tl);
+ o = ReadWord(tl->owner);
+ JS_ASSERT(Thin_GetWait(o) != 0);
+ JS_ASSERT(tl->fat != NULL);
+ if (!js_CompareAndSwap(&tl->owner, o, 0)) /* release it */
+ JS_ASSERT(0);
+ js_ResumeThread(tl);
+}
+
+JS_INLINE void
+js_Lock(JSThinLock *tl, jsword me)
+{
+ JS_ASSERT(me == CurrentThreadId());
+ if (js_CompareAndSwap(&tl->owner, 0, me))
+ return;
+ if (Thin_RemoveWait(ReadWord(tl->owner)) != me)
+ js_Enqueue(tl, me);
+#ifdef DEBUG
+ else
+ JS_ASSERT(0);
+#endif
+}
+
+JS_INLINE void
+js_Unlock(JSThinLock *tl, jsword me)
+{
+ JS_ASSERT(me == CurrentThreadId());
+ if (js_CompareAndSwap(&tl->owner, me, 0))
+ return;
+ if (Thin_RemoveWait(ReadWord(tl->owner)) == me)
+ js_Dequeue(tl);
+#ifdef DEBUG
+ else
+ JS_ASSERT(0);
+#endif
+}
+
+#endif /* !NSPR_LOCK */
+
+void
+js_LockRuntime(JSRuntime *rt)
+{
+ PR_Lock(rt->rtLock);
+#ifdef DEBUG
+ rt->rtLockOwner = CurrentThreadId();
+#endif
+}
+
+void
+js_UnlockRuntime(JSRuntime *rt)
+{
+#ifdef DEBUG
+ rt->rtLockOwner = 0;
+#endif
+ PR_Unlock(rt->rtLock);
+}
+
+void
+js_LockScope(JSContext *cx, JSScope *scope)
+{
+ jsword me = cx->thread;
+
+ JS_ASSERT(me == CurrentThreadId());
+ JS_ASSERT(scope->ownercx != cx);
+ if (CX_THREAD_IS_RUNNING_GC(cx))
+ return;
+ if (scope->ownercx && ClaimScope(scope, cx))
+ return;
+
+ if (Thin_RemoveWait(ReadWord(scope->lock.owner)) == me) {
+ JS_ASSERT(scope->u.count > 0);
+ LOGIT(scope, '+');
+ scope->u.count++;
+ } else {
+ JSThinLock *tl = &scope->lock;
+ JS_LOCK0(tl, me);
+ JS_ASSERT(scope->u.count == 0);
+ LOGIT(scope, '1');
+ scope->u.count = 1;
+ }
+}
+
+void
+js_UnlockScope(JSContext *cx, JSScope *scope)
+{
+ jsword me = cx->thread;
+
+ /* We hope compilers use me instead of reloading cx->thread in the macro. */
+ if (CX_THREAD_IS_RUNNING_GC(cx))
+ return;
+ if (cx->lockedSealedScope == scope) {
+ cx->lockedSealedScope = NULL;
+ return;
+ }
+
+ JS_ASSERT(scope->ownercx == NULL);
+ JS_ASSERT(scope->u.count > 0);
+ if (Thin_RemoveWait(ReadWord(scope->lock.owner)) != me) {
+ JS_ASSERT(0); /* unbalanced unlock */
+ return;
+ }
+ LOGIT(scope, '-');
+ if (--scope->u.count == 0) {
+ JSThinLock *tl = &scope->lock;
+ JS_UNLOCK0(tl, me);
+ }
+}
+
+/*
+ * NB: oldscope may be null if our caller is js_GetMutableScope and it just
+ * dropped the last reference to oldscope.
+ */
+void
+js_TransferScopeLock(JSContext *cx, JSScope *oldscope, JSScope *newscope)
+{
+ jsword me;
+ JSThinLock *tl;
+
+ JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, newscope));
+
+ /*
+ * If the last reference to oldscope went away, newscope needs no lock
+ * state update.
+ */
+ if (!oldscope)
+ return;
+ JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, oldscope));
+
+ /*
+ * Special case in js_LockScope and js_UnlockScope for the GC calling
+ * code that locks, unlocks, or mutates. Nothing to do in these cases,
+ * because scope and newscope were "locked" by the GC thread, so neither
+ * was actually locked.
+ */
+ if (CX_THREAD_IS_RUNNING_GC(cx))
+ return;
+
+ /*
+ * Special case in js_LockObj and js_UnlockScope for locking the sealed
+ * scope of an object that owns that scope (the prototype or mutated obj
+ * for which OBJ_SCOPE(obj)->object == obj), and unlocking it.
+ */
+ JS_ASSERT(cx->lockedSealedScope != newscope);
+ if (cx->lockedSealedScope == oldscope) {
+ JS_ASSERT(newscope->ownercx == cx ||
+ (!newscope->ownercx && newscope->u.count == 1));
+ cx->lockedSealedScope = NULL;
+ return;
+ }
+
+ /*
+ * If oldscope is single-threaded, there's nothing to do.
+ */
+ if (oldscope->ownercx) {
+ JS_ASSERT(oldscope->ownercx == cx);
+ JS_ASSERT(newscope->ownercx == cx ||
+ (!newscope->ownercx && newscope->u.count == 1));
+ return;
+ }
+
+ /*
+ * We transfer oldscope->u.count only if newscope is not single-threaded.
+ * Flow unwinds from here through some number of JS_UNLOCK_SCOPE and/or
+ * JS_UNLOCK_OBJ macro calls, which will decrement newscope->u.count only
+ * if they find newscope->ownercx != cx.
+ */
+ if (newscope->ownercx != cx) {
+ JS_ASSERT(!newscope->ownercx);
+ newscope->u.count = oldscope->u.count;
+ }
+
+ /*
+ * Reset oldscope's lock state so that it is completely unlocked.
+ */
+ LOGIT(oldscope, '0');
+ oldscope->u.count = 0;
+ tl = &oldscope->lock;
+ me = cx->thread;
+ JS_UNLOCK0(tl, me);
+}
+
+void
+js_LockObj(JSContext *cx, JSObject *obj)
+{
+ JSScope *scope;
+
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
+ for (;;) {
+ scope = OBJ_SCOPE(obj);
+ if (SCOPE_IS_SEALED(scope) && scope->object == obj &&
+ !cx->lockedSealedScope) {
+ cx->lockedSealedScope = scope;
+ return;
+ }
+
+ js_LockScope(cx, scope);
+
+ /* If obj still has this scope, we're done. */
+ if (scope == OBJ_SCOPE(obj))
+ return;
+
+ /* Lost a race with a mutator; retry with obj's new scope. */
+ js_UnlockScope(cx, scope);
+ }
+}
+
+void
+js_UnlockObj(JSContext *cx, JSObject *obj)
+{
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
+ js_UnlockScope(cx, OBJ_SCOPE(obj));
+}
+
+#ifdef DEBUG
+
+JSBool
+js_IsRuntimeLocked(JSRuntime *rt)
+{
+ return CurrentThreadId() == rt->rtLockOwner;
+}
+
+JSBool
+js_IsObjLocked(JSContext *cx, JSObject *obj)
+{
+ JSScope *scope = OBJ_SCOPE(obj);
+
+ return MAP_IS_NATIVE(&scope->map) && js_IsScopeLocked(cx, scope);
+}
+
+JSBool
+js_IsScopeLocked(JSContext *cx, JSScope *scope)
+{
+ /* Special case: the GC locking any object's scope, see js_LockScope. */
+ if (CX_THREAD_IS_RUNNING_GC(cx))
+ return JS_TRUE;
+
+ /* Special case: locked object owning a sealed scope, see js_LockObj. */
+ if (cx->lockedSealedScope == scope)
+ return JS_TRUE;
+
+ /*
+ * General case: the scope is either exclusively owned (by cx), or it has
+ * a thin or fat lock to cope with shared (concurrent) ownership.
+ */
+ if (scope->ownercx) {
+ JS_ASSERT(scope->ownercx == cx);
+ return JS_TRUE;
+ }
+ return CurrentThreadId() == Thin_RemoveWait(ReadWord(scope->lock.owner));
+}
+
+#endif /* DEBUG */
+#endif /* JS_THREADSAFE */
diff --git a/src/dom/js/jslock.h b/src/dom/js/jslock.h
new file mode 100644
index 000000000..9ece59c9b
--- /dev/null
+++ b/src/dom/js/jslock.h
@@ -0,0 +1,289 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef jslock_h__
+#define jslock_h__
+
+#ifdef JS_THREADSAFE
+
+#include "jstypes.h"
+#include "pratom.h"
+#include "prlock.h"
+#include "prcvar.h"
+
+#include "jsprvtd.h" /* for JSScope, etc. */
+#include "jspubtd.h" /* for JSRuntime, etc. */
+
+#define Thin_GetWait(W) ((jsword)(W) & 0x1)
+#define Thin_SetWait(W) ((jsword)(W) | 0x1)
+#define Thin_RemoveWait(W) ((jsword)(W) & ~0x1)
+
+typedef struct JSFatLock JSFatLock;
+
+struct JSFatLock {
+ int susp;
+ PRLock *slock;
+ PRCondVar *svar;
+ JSFatLock *next;
+ JSFatLock **prevp;
+};
+
+typedef struct JSThinLock {
+ jsword owner;
+ JSFatLock *fat;
+} JSThinLock;
+
+typedef PRLock JSLock;
+
+typedef struct JSFatLockTable {
+ JSFatLock *free;
+ JSFatLock *taken;
+} JSFatLockTable;
+
+/*
+ * Atomic increment and decrement for a reference counter, given jsrefcount *p.
+ * NB: jsrefcount is int32, aka PRInt32, so that pratom.h functions work.
+ */
+#define JS_ATOMIC_INCREMENT(p) PR_AtomicIncrement((PRInt32 *)(p))
+#define JS_ATOMIC_DECREMENT(p) PR_AtomicDecrement((PRInt32 *)(p))
+#define JS_ATOMIC_ADD(p,v) PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v))
+
+#define CurrentThreadId() (jsword)PR_GetCurrentThread()
+#define JS_CurrentThreadId() js_CurrentThreadId()
+#define JS_NEW_LOCK() PR_NewLock()
+#define JS_DESTROY_LOCK(l) PR_DestroyLock(l)
+#define JS_ACQUIRE_LOCK(l) PR_Lock(l)
+#define JS_RELEASE_LOCK(l) PR_Unlock(l)
+#define JS_LOCK0(P,M) js_Lock(P,M)
+#define JS_UNLOCK0(P,M) js_Unlock(P,M)
+
+#define JS_NEW_CONDVAR(l) PR_NewCondVar(l)
+#define JS_DESTROY_CONDVAR(cv) PR_DestroyCondVar(cv)
+#define JS_WAIT_CONDVAR(cv,to) PR_WaitCondVar(cv,to)
+#define JS_NO_TIMEOUT PR_INTERVAL_NO_TIMEOUT
+#define JS_NOTIFY_CONDVAR(cv) PR_NotifyCondVar(cv)
+#define JS_NOTIFY_ALL_CONDVAR(cv) PR_NotifyAllCondVar(cv)
+
+/*
+ * Include jsscope.h so JS_LOCK_OBJ macro callers don't have to include it.
+ * Since there is a JSThinLock member in JSScope, we can't nest this include
+ * much earlier (see JSThinLock's typedef, above). Yes, that means there is
+ * an #include cycle between jslock.h and jsscope.h: moderate-sized XXX here,
+ * to be fixed by moving JS_LOCK_SCOPE to jsscope.h, JS_LOCK_OBJ to jsobj.h,
+ * and so on.
+ *
+ * We also need jsscope.h #ifdef DEBUG for SET_OBJ_INFO and SET_SCOPE_INFO,
+ * but we do not want any nested includes that depend on DEBUG. Those lead
+ * to build bustage when someone makes a change that depends in a subtle way
+ * on jsscope.h being included directly or indirectly, but does not test by
+ * building optimized as well as DEBUG.
+ */
+#include "jsscope.h"
+
+#ifdef DEBUG
+
+#define SET_OBJ_INFO(obj_,file_,line_) \
+ SET_SCOPE_INFO(OBJ_SCOPE(obj_),file_,line_)
+
+#define SET_SCOPE_INFO(scope_,file_,line_) \
+ ((scope_)->ownercx ? (void)0 : \
+ (JS_ASSERT((0 < (scope_)->u.count && (scope_)->u.count <= 4) || \
+ SCOPE_IS_SEALED(scope_)), \
+ (void)((scope_)->file[(scope_)->u.count-1] = (file_), \
+ (scope_)->line[(scope_)->u.count-1] = (line_))))
+#endif /* DEBUG */
+
+#define JS_LOCK_RUNTIME(rt) js_LockRuntime(rt)
+#define JS_UNLOCK_RUNTIME(rt) js_UnlockRuntime(rt)
+
+/*
+ * NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects
+ * (objects for which OBJ_IS_NATIVE returns true). All uses of these macros in
+ * the engine are predicated on OBJ_IS_NATIVE or equivalent checks. These uses
+ * are for optimizations above the JSObjectOps layer, under which object locks
+ * normally hide.
+ */
+#define JS_LOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->ownercx == (cx)) \
+ ? (void)0 \
+ : (js_LockObj(cx, obj), \
+ SET_OBJ_INFO(obj,__FILE__,__LINE__)))
+#define JS_UNLOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->ownercx == (cx)) \
+ ? (void)0 : js_UnlockObj(cx, obj))
+
+#define JS_LOCK_SCOPE(cx,scope) ((scope)->ownercx == (cx) ? (void)0 : \
+ (js_LockScope(cx, scope), \
+ SET_SCOPE_INFO(scope,__FILE__,__LINE__)))
+#define JS_UNLOCK_SCOPE(cx,scope) ((scope)->ownercx == (cx) ? (void)0 : \
+ js_UnlockScope(cx, scope))
+#define JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope) \
+ js_TransferScopeLock(cx, scope, newscope)
+
+extern jsword js_CurrentThreadId();
+extern void js_LockRuntime(JSRuntime *rt);
+extern void js_UnlockRuntime(JSRuntime *rt);
+extern void js_LockObj(JSContext *cx, JSObject *obj);
+extern void js_UnlockObj(JSContext *cx, JSObject *obj);
+extern void js_LockScope(JSContext *cx, JSScope *scope);
+extern void js_UnlockScope(JSContext *cx, JSScope *scope);
+extern int js_SetupLocks(int,int);
+extern void js_CleanupLocks();
+extern void js_InitContextForLocking(JSContext *);
+extern void js_TransferScopeLock(JSContext *, JSScope *, JSScope *);
+extern JS_FRIEND_API(jsval)
+js_GetSlotThreadSafe(JSContext *, JSObject *, uint32);
+extern void js_SetSlotThreadSafe(JSContext *, JSObject *, uint32, jsval);
+extern void js_InitLock(JSThinLock *);
+extern void js_FinishLock(JSThinLock *);
+extern void js_FinishSharingScope(JSRuntime *rt, JSScope *scope);
+
+#ifdef DEBUG
+
+#define JS_IS_RUNTIME_LOCKED(rt) js_IsRuntimeLocked(rt)
+#define JS_IS_OBJ_LOCKED(cx,obj) js_IsObjLocked(cx,obj)
+#define JS_IS_SCOPE_LOCKED(cx,scope) js_IsScopeLocked(cx,scope)
+
+extern JSBool js_IsRuntimeLocked(JSRuntime *rt);
+extern JSBool js_IsObjLocked(JSContext *cx, JSObject *obj);
+extern JSBool js_IsScopeLocked(JSContext *cx, JSScope *scope);
+
+#else
+
+#define JS_IS_RUNTIME_LOCKED(rt) 0
+#define JS_IS_OBJ_LOCKED(cx,obj) 1
+#define JS_IS_SCOPE_LOCKED(cx,scope) 1
+
+#endif /* DEBUG */
+
+#define JS_LOCK_OBJ_VOID(cx, obj, e) \
+ JS_BEGIN_MACRO \
+ JS_LOCK_OBJ(cx, obj); \
+ e; \
+ JS_UNLOCK_OBJ(cx, obj); \
+ JS_END_MACRO
+
+#define JS_LOCK_VOID(cx, e) \
+ JS_BEGIN_MACRO \
+ JSRuntime *_rt = (cx)->runtime; \
+ JS_LOCK_RUNTIME_VOID(_rt, e); \
+ JS_END_MACRO
+
+#if defined(JS_USE_ONLY_NSPR_LOCKS) || \
+ !( (defined(_WIN32) && defined(_M_IX86)) || \
+ (defined(__GNUC__) && defined(__i386__)) || \
+ (defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)) || \
+ defined(AIX) )
+
+#define NSPR_LOCK 1
+
+#undef JS_LOCK0
+#undef JS_UNLOCK0
+#define JS_LOCK0(P,M) (JS_ACQUIRE_LOCK(((JSLock*)(P)->fat)), (P)->owner = (M))
+#define JS_UNLOCK0(P,M) ((P)->owner = 0, JS_RELEASE_LOCK(((JSLock*)(P)->fat)))
+
+#else /* arch-tests */
+
+#undef NSPR_LOCK
+
+extern JS_INLINE void js_Lock(JSThinLock *tl, jsword me);
+extern JS_INLINE void js_Unlock(JSThinLock *tl, jsword me);
+
+#endif /* arch-tests */
+
+#else /* !JS_THREADSAFE */
+
+#define JS_ATOMIC_INCREMENT(p) (++*(p))
+#define JS_ATOMIC_DECREMENT(p) (--*(p))
+#define JS_ATOMIC_ADD(p,v) (*(p) += (v))
+
+#define JS_CurrentThreadId() 0
+#define JS_NEW_LOCK() NULL
+#define JS_DESTROY_LOCK(l) ((void)0)
+#define JS_ACQUIRE_LOCK(l) ((void)0)
+#define JS_RELEASE_LOCK(l) ((void)0)
+#define JS_LOCK0(P,M) ((void)0)
+#define JS_UNLOCK0(P,M) ((void)0)
+
+#define JS_NEW_CONDVAR(l) NULL
+#define JS_DESTROY_CONDVAR(cv) ((void)0)
+#define JS_WAIT_CONDVAR(cv,to) ((void)0)
+#define JS_NOTIFY_CONDVAR(cv) ((void)0)
+#define JS_NOTIFY_ALL_CONDVAR(cv) ((void)0)
+
+#define JS_LOCK_RUNTIME(rt) ((void)0)
+#define JS_UNLOCK_RUNTIME(rt) ((void)0)
+#define JS_LOCK_OBJ(cx,obj) ((void)0)
+#define JS_UNLOCK_OBJ(cx,obj) ((void)0)
+#define JS_LOCK_OBJ_VOID(cx,obj,e) (e)
+#define JS_LOCK_SCOPE(cx,scope) ((void)0)
+#define JS_UNLOCK_SCOPE(cx,scope) ((void)0)
+#define JS_TRANSFER_SCOPE_LOCK(c,o,n) ((void)0)
+
+#define JS_IS_RUNTIME_LOCKED(rt) 1
+#define JS_IS_OBJ_LOCKED(cx,obj) 1
+#define JS_IS_SCOPE_LOCKED(cx,scope) 1
+#define JS_LOCK_VOID(cx, e) JS_LOCK_RUNTIME_VOID((cx)->runtime, e)
+
+#endif /* !JS_THREADSAFE */
+
+#define JS_LOCK_RUNTIME_VOID(rt,e) \
+ JS_BEGIN_MACRO \
+ JS_LOCK_RUNTIME(rt); \
+ e; \
+ JS_UNLOCK_RUNTIME(rt); \
+ JS_END_MACRO
+
+#define JS_LOCK_GC(rt) JS_ACQUIRE_LOCK((rt)->gcLock)
+#define JS_UNLOCK_GC(rt) JS_RELEASE_LOCK((rt)->gcLock)
+#define JS_LOCK_GC_VOID(rt,e) (JS_LOCK_GC(rt), (e), JS_UNLOCK_GC(rt))
+#define JS_AWAIT_GC_DONE(rt) JS_WAIT_CONDVAR((rt)->gcDone, JS_NO_TIMEOUT)
+#define JS_NOTIFY_GC_DONE(rt) JS_NOTIFY_ALL_CONDVAR((rt)->gcDone)
+#define JS_AWAIT_REQUEST_DONE(rt) JS_WAIT_CONDVAR((rt)->requestDone, \
+ JS_NO_TIMEOUT)
+#define JS_NOTIFY_REQUEST_DONE(rt) JS_NOTIFY_CONDVAR((rt)->requestDone)
+
+#define JS_LOCK(P,CX) JS_LOCK0(P,(CX)->thread)
+#define JS_UNLOCK(P,CX) JS_UNLOCK0(P,(CX)->thread)
+
+#ifndef SET_OBJ_INFO
+#define SET_OBJ_INFO(obj,f,l) ((void)0)
+#endif
+#ifndef SET_SCOPE_INFO
+#define SET_SCOPE_INFO(scope,f,l) ((void)0)
+#endif
+
+#endif /* jslock_h___ */
diff --git a/src/dom/js/jslocko.asm b/src/dom/js/jslocko.asm
new file mode 100644
index 000000000..2589bb7f9
--- /dev/null
+++ b/src/dom/js/jslocko.asm
@@ -0,0 +1,59 @@
+COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*-
+***** BEGIN LICENSE BLOCK *****
+Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is an OS/2 implementation of js_CompareAndSwap in assembly
+
+The Initial Developer of the Original Code is IBM Corporation.
+Portions created by the Initial Developer are Copyright (C) 2001
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+
+***** END LICENSE BLOCK *****
+ |
+
+ .486P
+ .MODEL FLAT, OPTLINK
+ .STACK
+
+ .CODE
+
+;;;---------------------------------------------------------------------
+;;; int _Optlink js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
+;;;---------------------------------------------------------------------
+js_CompareAndSwap PROC OPTLINK EXPORT
+ push ebx
+ mov ebx, eax
+ mov eax, edx
+ mov edx, ebx
+ lock cmpxchg [ebx], ecx
+ sete al
+ and eax, 1h
+ pop ebx
+ ret
+js_CompareAndSwap endp
+
+ END
diff --git a/src/dom/js/jslog2.c b/src/dom/js/jslog2.c
new file mode 100644
index 000000000..113c276d0
--- /dev/null
+++ b/src/dom/js/jslog2.c
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "jsstddef.h"
+#include "jsbit.h"
+
+/*
+** Compute the log of the least power of 2 greater than or equal to n
+*/
+JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 n)
+{
+ JSIntn log2 = 0;
+
+ if (n & (n-1))
+ log2++;
+ if (n >> 16)
+ log2 += 16, n >>= 16;
+ if (n >> 8)
+ log2 += 8, n >>= 8;
+ if (n >> 4)
+ log2 += 4, n >>= 4;
+ if (n >> 2)
+ log2 += 2, n >>= 2;
+ if (n >> 1)
+ log2++;
+ return log2;
+}
+
+/*
+** Compute the log of the greatest power of 2 less than or equal to n.
+** This really just finds the highest set bit in the word.
+*/
+JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 n)
+{
+ JSIntn log2 = 0;
+
+ if (n >> 16)
+ log2 += 16, n >>= 16;
+ if (n >> 8)
+ log2 += 8, n >>= 8;
+ if (n >> 4)
+ log2 += 4, n >>= 4;
+ if (n >> 2)
+ log2 += 2, n >>= 2;
+ if (n >> 1)
+ log2++;
+ return log2;
+}
diff --git a/src/dom/js/jslong.c b/src/dom/js/jslong.c
new file mode 100644
index 000000000..76259e502
--- /dev/null
+++ b/src/dom/js/jslong.c
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "jsstddef.h"
+#include "jstypes.h"
+#include "jslong.h"
+
+static JSInt64 ll_zero = JSLL_INIT( 0x00000000,0x00000000 );
+static JSInt64 ll_maxint = JSLL_INIT( 0x7fffffff, 0xffffffff );
+static JSInt64 ll_minint = JSLL_INIT( 0x80000000, 0x00000000 );
+
+#ifdef HAVE_WATCOM_BUG_2
+JSInt64 __pascal __loadds __export
+ JSLL_Zero(void) { return ll_zero; }
+JSInt64 __pascal __loadds __export
+ JSLL_MaxInt(void) { return ll_maxint; }
+JSInt64 __pascal __loadds __export
+ JSLL_MinInt(void) { return ll_minint; }
+#else
+JS_PUBLIC_API(JSInt64) JSLL_Zero(void) { return ll_zero; }
+JS_PUBLIC_API(JSInt64) JSLL_MaxInt(void) { return ll_maxint; }
+JS_PUBLIC_API(JSInt64) JSLL_MinInt(void) { return ll_minint; }
+#endif
+
+#ifndef JS_HAVE_LONG_LONG
+/*
+** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1.
+*/
+static void norm_udivmod32(JSUint32 *qp, JSUint32 *rp, JSUint64 a, JSUint32 b)
+{
+ JSUint32 d1, d0, q1, q0;
+ JSUint32 r1, r0, m;
+
+ d1 = jshi16(b);
+ d0 = jslo16(b);
+ r1 = a.hi % d1;
+ q1 = a.hi / d1;
+ m = q1 * d0;
+ r1 = (r1 << 16) | jshi16(a.lo);
+ if (r1 < m) {
+ q1--, r1 += b;
+ if (r1 >= b /* i.e., we didn't get a carry when adding to r1 */
+ && r1 < m) {
+ q1--, r1 += b;
+ }
+ }
+ r1 -= m;
+ r0 = r1 % d1;
+ q0 = r1 / d1;
+ m = q0 * d0;
+ r0 = (r0 << 16) | jslo16(a.lo);
+ if (r0 < m) {
+ q0--, r0 += b;
+ if (r0 >= b
+ && r0 < m) {
+ q0--, r0 += b;
+ }
+ }
+ *qp = (q1 << 16) | q0;
+ *rp = r0 - m;
+}
+
+static JSUint32 CountLeadingZeros(JSUint32 a)
+{
+ JSUint32 t;
+ JSUint32 r = 32;
+
+ if ((t = a >> 16) != 0)
+ r -= 16, a = t;
+ if ((t = a >> 8) != 0)
+ r -= 8, a = t;
+ if ((t = a >> 4) != 0)
+ r -= 4, a = t;
+ if ((t = a >> 2) != 0)
+ r -= 2, a = t;
+ if ((t = a >> 1) != 0)
+ r -= 1, a = t;
+ if (a & 1)
+ r--;
+ return r;
+}
+
+JS_PUBLIC_API(void) jsll_udivmod(JSUint64 *qp, JSUint64 *rp, JSUint64 a, JSUint64 b)
+{
+ JSUint32 n0, n1, n2;
+ JSUint32 q0, q1;
+ JSUint32 rsh, lsh;
+
+ n0 = a.lo;
+ n1 = a.hi;
+
+ if (b.hi == 0) {
+ if (b.lo > n1) {
+ /* (0 q0) = (n1 n0) / (0 D0) */
+
+ lsh = CountLeadingZeros(b.lo);
+
+ if (lsh) {
+ /*
+ * Normalize, i.e. make the most significant bit of the
+ * denominator be set.
+ */
+ b.lo = b.lo << lsh;
+ n1 = (n1 << lsh) | (n0 >> (32 - lsh));
+ n0 = n0 << lsh;
+ }
+
+ a.lo = n0, a.hi = n1;
+ norm_udivmod32(&q0, &n0, a, b.lo);
+ q1 = 0;
+
+ /* remainder is in n0 >> lsh */
+ } else {
+ /* (q1 q0) = (n1 n0) / (0 d0) */
+
+ if (b.lo == 0) /* user wants to divide by zero! */
+ b.lo = 1 / b.lo; /* so go ahead and crash */
+
+ lsh = CountLeadingZeros(b.lo);
+
+ if (lsh == 0) {
+ /*
+ * From (n1 >= b.lo)
+ * && (the most significant bit of b.lo is set),
+ * conclude that
+ * (the most significant bit of n1 is set)
+ * && (the leading quotient digit q1 = 1).
+ *
+ * This special case is necessary, not an optimization
+ * (Shifts counts of 32 are undefined).
+ */
+ n1 -= b.lo;
+ q1 = 1;
+ } else {
+ /*
+ * Normalize.
+ */
+ rsh = 32 - lsh;
+
+ b.lo = b.lo << lsh;
+ n2 = n1 >> rsh;
+ n1 = (n1 << lsh) | (n0 >> rsh);
+ n0 = n0 << lsh;
+
+ a.lo = n1, a.hi = n2;
+ norm_udivmod32(&q1, &n1, a, b.lo);
+ }
+
+ /* n1 != b.lo... */
+
+ a.lo = n0, a.hi = n1;
+ norm_udivmod32(&q0, &n0, a, b.lo);
+
+ /* remainder in n0 >> lsh */
+ }
+
+ if (rp) {
+ rp->lo = n0 >> lsh;
+ rp->hi = 0;
+ }
+ } else {
+ if (b.hi > n1) {
+ /* (0 0) = (n1 n0) / (D1 d0) */
+
+ q0 = 0;
+ q1 = 0;
+
+ /* remainder in (n1 n0) */
+ if (rp) {
+ rp->lo = n0;
+ rp->hi = n1;
+ }
+ } else {
+ /* (0 q0) = (n1 n0) / (d1 d0) */
+
+ lsh = CountLeadingZeros(b.hi);
+ if (lsh == 0) {
+ /*
+ * From (n1 >= b.hi)
+ * && (the most significant bit of b.hi is set),
+ * conclude that
+ * (the most significant bit of n1 is set)
+ * && (the quotient digit q0 = 0 or 1).
+ *
+ * This special case is necessary, not an optimization.
+ */
+
+ /*
+ * The condition on the next line takes advantage of that
+ * n1 >= b.hi (true due to control flow).
+ */
+ if (n1 > b.hi || n0 >= b.lo) {
+ q0 = 1;
+ a.lo = n0, a.hi = n1;
+ JSLL_SUB(a, a, b);
+ } else {
+ q0 = 0;
+ }
+ q1 = 0;
+
+ if (rp) {
+ rp->lo = n0;
+ rp->hi = n1;
+ }
+ } else {
+ JSInt64 m;
+
+ /*
+ * Normalize.
+ */
+ rsh = 32 - lsh;
+
+ b.hi = (b.hi << lsh) | (b.lo >> rsh);
+ b.lo = b.lo << lsh;
+ n2 = n1 >> rsh;
+ n1 = (n1 << lsh) | (n0 >> rsh);
+ n0 = n0 << lsh;
+
+ a.lo = n1, a.hi = n2;
+ norm_udivmod32(&q0, &n1, a, b.hi);
+ JSLL_MUL32(m, q0, b.lo);
+
+ if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) {
+ q0--;
+ JSLL_SUB(m, m, b);
+ }
+
+ q1 = 0;
+
+ /* Remainder is ((n1 n0) - (m1 m0)) >> lsh */
+ if (rp) {
+ a.lo = n0, a.hi = n1;
+ JSLL_SUB(a, a, m);
+ rp->lo = (a.hi << rsh) | (a.lo >> lsh);
+ rp->hi = a.hi >> lsh;
+ }
+ }
+ }
+ }
+
+ if (qp) {
+ qp->lo = q0;
+ qp->hi = q1;
+ }
+}
+#endif /* !JS_HAVE_LONG_LONG */
diff --git a/src/dom/js/jslong.h b/src/dom/js/jslong.h
new file mode 100644
index 000000000..bde8bfbbf
--- /dev/null
+++ b/src/dom/js/jslong.h
@@ -0,0 +1,437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** File: jslong.h
+** Description: Portable access to 64 bit numerics
+**
+** Long-long (64-bit signed integer type) support. Some C compilers
+** don't support 64 bit integers yet, so we use these macros to
+** support both machines that do and don't.
+**/
+#ifndef jslong_h___
+#define jslong_h___
+
+#include "jstypes.h"
+
+JS_BEGIN_EXTERN_C
+
+/***********************************************************************
+** DEFINES: JSLL_MaxInt
+** JSLL_MinInt
+** JSLL_Zero
+** DESCRIPTION:
+** Various interesting constants and static variable
+** initializer
+***********************************************************************/
+#ifdef HAVE_WATCOM_BUG_2
+JSInt64 __pascal __loadds __export
+ JSLL_MaxInt(void);
+JSInt64 __pascal __loadds __export
+ JSLL_MinInt(void);
+JSInt64 __pascal __loadds __export
+ JSLL_Zero(void);
+#else
+extern JS_PUBLIC_API(JSInt64) JSLL_MaxInt(void);
+extern JS_PUBLIC_API(JSInt64) JSLL_MinInt(void);
+extern JS_PUBLIC_API(JSInt64) JSLL_Zero(void);
+#endif
+
+#define JSLL_MAXINT JSLL_MaxInt()
+#define JSLL_MININT JSLL_MinInt()
+#define JSLL_ZERO JSLL_Zero()
+
+#ifdef JS_HAVE_LONG_LONG
+
+#if JS_BYTES_PER_LONG == 8
+#define JSLL_INIT(hi, lo) ((hi ## L << 32) + lo ## L)
+#elif (defined(WIN32) || defined(WIN16)) && !defined(__GNUC__)
+#define JSLL_INIT(hi, lo) ((hi ## i64 << 32) + lo ## i64)
+#else
+#define JSLL_INIT(hi, lo) ((hi ## LL << 32) + lo ## LL)
+#endif
+
+/***********************************************************************
+** MACROS: JSLL_*
+** DESCRIPTION:
+** The following macros define portable access to the 64 bit
+** math facilities.
+**
+***********************************************************************/
+
+/***********************************************************************
+** MACROS: JSLL_<relational operators>
+**
+** JSLL_IS_ZERO Test for zero
+** JSLL_EQ Test for equality
+** JSLL_NE Test for inequality
+** JSLL_GE_ZERO Test for zero or positive
+** JSLL_CMP Compare two values
+***********************************************************************/
+#define JSLL_IS_ZERO(a) ((a) == 0)
+#define JSLL_EQ(a, b) ((a) == (b))
+#define JSLL_NE(a, b) ((a) != (b))
+#define JSLL_GE_ZERO(a) ((a) >= 0)
+#define JSLL_CMP(a, op, b) ((JSInt64)(a) op (JSInt64)(b))
+#define JSLL_UCMP(a, op, b) ((JSUint64)(a) op (JSUint64)(b))
+
+/***********************************************************************
+** MACROS: JSLL_<logical operators>
+**
+** JSLL_AND Logical and
+** JSLL_OR Logical or
+** JSLL_XOR Logical exclusion
+** JSLL_OR2 A disgusting deviation
+** JSLL_NOT Negation (one's compliment)
+***********************************************************************/
+#define JSLL_AND(r, a, b) ((r) = (a) & (b))
+#define JSLL_OR(r, a, b) ((r) = (a) | (b))
+#define JSLL_XOR(r, a, b) ((r) = (a) ^ (b))
+#define JSLL_OR2(r, a) ((r) = (r) | (a))
+#define JSLL_NOT(r, a) ((r) = ~(a))
+
+/***********************************************************************
+** MACROS: JSLL_<mathematical operators>
+**
+** JSLL_NEG Negation (two's compliment)
+** JSLL_ADD Summation (two's compliment)
+** JSLL_SUB Difference (two's compliment)
+***********************************************************************/
+#define JSLL_NEG(r, a) ((r) = -(a))
+#define JSLL_ADD(r, a, b) ((r) = (a) + (b))
+#define JSLL_SUB(r, a, b) ((r) = (a) - (b))
+
+/***********************************************************************
+** MACROS: JSLL_<mathematical operators>
+**
+** JSLL_MUL Product (two's compliment)
+** JSLL_DIV Quotient (two's compliment)
+** JSLL_MOD Modulus (two's compliment)
+***********************************************************************/
+#define JSLL_MUL(r, a, b) ((r) = (a) * (b))
+#define JSLL_DIV(r, a, b) ((r) = (a) / (b))
+#define JSLL_MOD(r, a, b) ((r) = (a) % (b))
+
+/***********************************************************************
+** MACROS: JSLL_<shifting operators>
+**
+** JSLL_SHL Shift left [0..64] bits
+** JSLL_SHR Shift right [0..64] bits with sign extension
+** JSLL_USHR Unsigned shift right [0..64] bits
+** JSLL_ISHL Signed shift left [0..64] bits
+***********************************************************************/
+#define JSLL_SHL(r, a, b) ((r) = (JSInt64)(a) << (b))
+#define JSLL_SHR(r, a, b) ((r) = (JSInt64)(a) >> (b))
+#define JSLL_USHR(r, a, b) ((r) = (JSUint64)(a) >> (b))
+#define JSLL_ISHL(r, a, b) ((r) = (JSInt64)(a) << (b))
+
+/***********************************************************************
+** MACROS: JSLL_<conversion operators>
+**
+** JSLL_L2I Convert to signed 32 bit
+** JSLL_L2UI Convert to unsigned 32 bit
+** JSLL_L2F Convert to floating point
+** JSLL_L2D Convert to floating point
+** JSLL_I2L Convert signed to 64 bit
+** JSLL_UI2L Convert unsigned to 64 bit
+** JSLL_F2L Convert float to 64 bit
+** JSLL_D2L Convert float to 64 bit
+***********************************************************************/
+#define JSLL_L2I(i, l) ((i) = (JSInt32)(l))
+#define JSLL_L2UI(ui, l) ((ui) = (JSUint32)(l))
+#define JSLL_L2F(f, l) ((f) = (JSFloat64)(l))
+#define JSLL_L2D(d, l) ((d) = (JSFloat64)(l))
+
+#define JSLL_I2L(l, i) ((l) = (JSInt64)(i))
+#define JSLL_UI2L(l, ui) ((l) = (JSInt64)(ui))
+#define JSLL_F2L(l, f) ((l) = (JSInt64)(f))
+#define JSLL_D2L(l, d) ((l) = (JSInt64)(d))
+
+/***********************************************************************
+** MACROS: JSLL_UDIVMOD
+** DESCRIPTION:
+** Produce both a quotient and a remainder given an unsigned
+** INPUTS: JSUint64 a: The dividend of the operation
+** JSUint64 b: The quotient of the operation
+** OUTPUTS: JSUint64 *qp: pointer to quotient
+** JSUint64 *rp: pointer to remainder
+***********************************************************************/
+#define JSLL_UDIVMOD(qp, rp, a, b) \
+ (*(qp) = ((JSUint64)(a) / (b)), \
+ *(rp) = ((JSUint64)(a) % (b)))
+
+#else /* !JS_HAVE_LONG_LONG */
+
+#ifdef IS_LITTLE_ENDIAN
+#define JSLL_INIT(hi, lo) {JS_INT32(lo), JS_INT32(hi)}
+#else
+#define JSLL_INIT(hi, lo) {JS_INT32(hi), JS_INT32(lo)}
+#endif
+
+#define JSLL_IS_ZERO(a) (((a).hi == 0) && ((a).lo == 0))
+#define JSLL_EQ(a, b) (((a).hi == (b).hi) && ((a).lo == (b).lo))
+#define JSLL_NE(a, b) (((a).hi != (b).hi) || ((a).lo != (b).lo))
+#define JSLL_GE_ZERO(a) (((a).hi >> 31) == 0)
+
+#ifdef DEBUG
+#define JSLL_CMP(a, op, b) (JS_ASSERT((#op)[1] != '='), JSLL_REAL_CMP(a, op, b))
+#define JSLL_UCMP(a, op, b) (JS_ASSERT((#op)[1] != '='), JSLL_REAL_UCMP(a, op, b))
+#else
+#define JSLL_CMP(a, op, b) JSLL_REAL_CMP(a, op, b)
+#define JSLL_UCMP(a, op, b) JSLL_REAL_UCMP(a, op, b)
+#endif
+
+#define JSLL_REAL_CMP(a,op,b) (((JSInt32)(a).hi op (JSInt32)(b).hi) || \
+ (((a).hi == (b).hi) && ((a).lo op (b).lo)))
+#define JSLL_REAL_UCMP(a,op,b) (((a).hi op (b).hi) || \
+ (((a).hi == (b).hi) && ((a).lo op (b).lo)))
+
+#define JSLL_AND(r, a, b) ((r).lo = (a).lo & (b).lo, \
+ (r).hi = (a).hi & (b).hi)
+#define JSLL_OR(r, a, b) ((r).lo = (a).lo | (b).lo, \
+ (r).hi = (a).hi | (b).hi)
+#define JSLL_XOR(r, a, b) ((r).lo = (a).lo ^ (b).lo, \
+ (r).hi = (a).hi ^ (b).hi)
+#define JSLL_OR2(r, a) ((r).lo = (r).lo | (a).lo, \
+ (r).hi = (r).hi | (a).hi)
+#define JSLL_NOT(r, a) ((r).lo = ~(a).lo, \
+ (r).hi = ~(a).hi)
+
+#define JSLL_NEG(r, a) ((r).lo = -(JSInt32)(a).lo, \
+ (r).hi = -(JSInt32)(a).hi - ((r).lo != 0))
+#define JSLL_ADD(r, a, b) { \
+ JSInt64 _a, _b; \
+ _a = a; _b = b; \
+ (r).lo = _a.lo + _b.lo; \
+ (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \
+}
+
+#define JSLL_SUB(r, a, b) { \
+ JSInt64 _a, _b; \
+ _a = a; _b = b; \
+ (r).lo = _a.lo - _b.lo; \
+ (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \
+}
+
+#define JSLL_MUL(r, a, b) { \
+ JSInt64 _a, _b; \
+ _a = a; _b = b; \
+ JSLL_MUL32(r, _a.lo, _b.lo); \
+ (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \
+}
+
+#define jslo16(a) ((a) & JS_BITMASK(16))
+#define jshi16(a) ((a) >> 16)
+
+#define JSLL_MUL32(r, a, b) { \
+ JSUint32 _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \
+ _a1 = jshi16(a), _a0 = jslo16(a); \
+ _b1 = jshi16(b), _b0 = jslo16(b); \
+ _y0 = _a0 * _b0; \
+ _y1 = _a0 * _b1; \
+ _y2 = _a1 * _b0; \
+ _y3 = _a1 * _b1; \
+ _y1 += jshi16(_y0); /* can't carry */ \
+ _y1 += _y2; /* might carry */ \
+ if (_y1 < _y2) \
+ _y3 += (JSUint32)(JS_BIT(16)); /* propagate */ \
+ (r).lo = (jslo16(_y1) << 16) + jslo16(_y0); \
+ (r).hi = _y3 + jshi16(_y1); \
+}
+
+#define JSLL_UDIVMOD(qp, rp, a, b) jsll_udivmod(qp, rp, a, b)
+
+extern JS_PUBLIC_API(void) jsll_udivmod(JSUint64 *qp, JSUint64 *rp, JSUint64 a, JSUint64 b);
+
+#define JSLL_DIV(r, a, b) { \
+ JSInt64 _a, _b; \
+ JSUint32 _negative = (JSInt32)(a).hi < 0; \
+ if (_negative) { \
+ JSLL_NEG(_a, a); \
+ } else { \
+ _a = a; \
+ } \
+ if ((JSInt32)(b).hi < 0) { \
+ _negative ^= 1; \
+ JSLL_NEG(_b, b); \
+ } else { \
+ _b = b; \
+ } \
+ JSLL_UDIVMOD(&(r), 0, _a, _b); \
+ if (_negative) \
+ JSLL_NEG(r, r); \
+}
+
+#define JSLL_MOD(r, a, b) { \
+ JSInt64 _a, _b; \
+ JSUint32 _negative = (JSInt32)(a).hi < 0; \
+ if (_negative) { \
+ JSLL_NEG(_a, a); \
+ } else { \
+ _a = a; \
+ } \
+ if ((JSInt32)(b).hi < 0) { \
+ JSLL_NEG(_b, b); \
+ } else { \
+ _b = b; \
+ } \
+ JSLL_UDIVMOD(0, &(r), _a, _b); \
+ if (_negative) \
+ JSLL_NEG(r, r); \
+}
+
+#define JSLL_SHL(r, a, b) { \
+ if (b) { \
+ JSInt64 _a; \
+ _a = a; \
+ if ((b) < 32) { \
+ (r).lo = _a.lo << ((b) & 31); \
+ (r).hi = (_a.hi << ((b) & 31)) | (_a.lo >> (32 - (b))); \
+ } else { \
+ (r).lo = 0; \
+ (r).hi = _a.lo << ((b) & 31); \
+ } \
+ } else { \
+ (r) = (a); \
+ } \
+}
+
+/* a is an JSInt32, b is JSInt32, r is JSInt64 */
+#define JSLL_ISHL(r, a, b) { \
+ if (b) { \
+ JSInt64 _a; \
+ _a.lo = (a); \
+ _a.hi = 0; \
+ if ((b) < 32) { \
+ (r).lo = (a) << ((b) & 31); \
+ (r).hi = ((a) >> (32 - (b))); \
+ } else { \
+ (r).lo = 0; \
+ (r).hi = (a) << ((b) & 31); \
+ } \
+ } else { \
+ (r).lo = (a); \
+ (r).hi = 0; \
+ } \
+}
+
+#define JSLL_SHR(r, a, b) { \
+ if (b) { \
+ JSInt64 _a; \
+ _a = a; \
+ if ((b) < 32) { \
+ (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \
+ (r).hi = (JSInt32)_a.hi >> ((b) & 31); \
+ } else { \
+ (r).lo = (JSInt32)_a.hi >> ((b) & 31); \
+ (r).hi = (JSInt32)_a.hi >> 31; \
+ } \
+ } else { \
+ (r) = (a); \
+ } \
+}
+
+#define JSLL_USHR(r, a, b) { \
+ if (b) { \
+ JSInt64 _a; \
+ _a = a; \
+ if ((b) < 32) { \
+ (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \
+ (r).hi = _a.hi >> ((b) & 31); \
+ } else { \
+ (r).lo = _a.hi >> ((b) & 31); \
+ (r).hi = 0; \
+ } \
+ } else { \
+ (r) = (a); \
+ } \
+}
+
+#define JSLL_L2I(i, l) ((i) = (l).lo)
+#define JSLL_L2UI(ui, l) ((ui) = (l).lo)
+#define JSLL_L2F(f, l) { double _d; JSLL_L2D(_d, l); (f) = (JSFloat64)_d; }
+
+#define JSLL_L2D(d, l) { \
+ int _negative; \
+ JSInt64 _absval; \
+ \
+ _negative = (l).hi >> 31; \
+ if (_negative) { \
+ JSLL_NEG(_absval, l); \
+ } else { \
+ _absval = l; \
+ } \
+ (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \
+ if (_negative) \
+ (d) = -(d); \
+}
+
+#define JSLL_I2L(l, i) { JSInt32 _i = (i) >> 31; (l).lo = (i); (l).hi = _i; }
+#define JSLL_UI2L(l, ui) ((l).lo = (ui), (l).hi = 0)
+#define JSLL_F2L(l, f) { double _d = (double)f; JSLL_D2L(l, _d); }
+
+#define JSLL_D2L(l, d) { \
+ int _negative; \
+ double _absval, _d_hi; \
+ JSInt64 _lo_d; \
+ \
+ _negative = ((d) < 0); \
+ _absval = _negative ? -(d) : (d); \
+ \
+ (l).hi = _absval / 4.294967296e9; \
+ (l).lo = 0; \
+ JSLL_L2D(_d_hi, l); \
+ _absval -= _d_hi; \
+ _lo_d.hi = 0; \
+ if (_absval < 0) { \
+ _lo_d.lo = -_absval; \
+ JSLL_SUB(l, l, _lo_d); \
+ } else { \
+ _lo_d.lo = _absval; \
+ JSLL_ADD(l, l, _lo_d); \
+ } \
+ \
+ if (_negative) \
+ JSLL_NEG(l, l); \
+}
+
+#endif /* !JS_HAVE_LONG_LONG */
+
+JS_END_EXTERN_C
+
+#endif /* jslong_h___ */
diff --git a/src/dom/js/jsmath.c b/src/dom/js/jsmath.c
new file mode 100644
index 000000000..9c6fcec0e
--- /dev/null
+++ b/src/dom/js/jsmath.c
@@ -0,0 +1,477 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS math package.
+ */
+#include "jsstddef.h"
+#include "jslibmath.h"
+#include <stdlib.h>
+#include "jstypes.h"
+#include "jslong.h"
+#include "prmjtime.h"
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jslock.h"
+#include "jsmath.h"
+#include "jsnum.h"
+#include "jsobj.h"
+
+#ifndef M_E
+#define M_E 2.7182818284590452354
+#endif
+#ifndef M_LOG2E
+#define M_LOG2E 1.4426950408889634074
+#endif
+#ifndef M_LOG10E
+#define M_LOG10E 0.43429448190325182765
+#endif
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_LN10
+#define M_LN10 2.30258509299404568402
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440
+#endif
+
+static JSConstDoubleSpec math_constants[] = {
+ {M_E, "E", 0, {0,0,0}},
+ {M_LOG2E, "LOG2E", 0, {0,0,0}},
+ {M_LOG10E, "LOG10E", 0, {0,0,0}},
+ {M_LN2, "LN2", 0, {0,0,0}},
+ {M_LN10, "LN10", 0, {0,0,0}},
+ {M_PI, "PI", 0, {0,0,0}},
+ {M_SQRT2, "SQRT2", 0, {0,0,0}},
+ {M_SQRT1_2, "SQRT1_2", 0, {0,0,0}},
+ {0,0,0,{0,0,0}}
+};
+
+static JSClass math_class = {
+ "Math",
+ 0,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+static JSBool
+math_abs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_fabs(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_acos(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_acos(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_asin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+#ifdef XP_MAC
+ if (x == 0)
+ return js_NewNumberValue(cx, x, rval);
+#endif
+ z = fd_asin(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_atan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+#ifdef XP_MAC
+ if (x == 0)
+ return js_NewNumberValue(cx, x, rval);
+#endif
+ z = fd_atan(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_atan2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, y, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ if (!js_ValueToNumber(cx, argv[1], &y))
+ return JS_FALSE;
+ z = fd_atan2(x, y);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_ceil(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_ceil(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_cos(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_cos(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_exp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+#ifdef _WIN32
+ if (!JSDOUBLE_IS_NaN(x)) {
+ if (x == *cx->runtime->jsPositiveInfinity) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
+ return JS_TRUE;
+ }
+ if (x == *cx->runtime->jsNegativeInfinity) {
+ *rval = JSVAL_ZERO;
+ return JS_TRUE;
+ }
+ }
+#endif
+ z = fd_exp(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_floor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_floor(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_log(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_max(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z = *cx->runtime->jsNegativeInfinity;
+ uintN i;
+
+ if (argc == 0) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
+ return JS_TRUE;
+ }
+ for (i = 0; i < argc; i++) {
+ if (!js_ValueToNumber(cx, argv[i], &x))
+ return JS_FALSE;
+ if (JSDOUBLE_IS_NaN(x)) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ return JS_TRUE;
+ }
+ if ((x==0)&&(x==z)&&(fd_copysign(1.0,z)==-1))
+ z = x;
+ else
+ z = (x > z) ? x : z;
+ }
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_min(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z = *cx->runtime->jsPositiveInfinity;
+ uintN i;
+
+ if (argc == 0) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
+ return JS_TRUE;
+ }
+ for (i = 0; i < argc; i++) {
+ if (!js_ValueToNumber(cx, argv[i], &x))
+ return JS_FALSE;
+ if (JSDOUBLE_IS_NaN(x)) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ return JS_TRUE;
+ }
+ if ((x==0)&&(x==z)&&(fd_copysign(1.0,x)==-1))
+ z = x;
+ else
+ z = (x < z) ? x : z;
+ }
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_pow(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, y, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ if (!js_ValueToNumber(cx, argv[1], &y))
+ return JS_FALSE;
+ z = fd_pow(x, y);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+/*
+ * Math.random() support, lifted from java.util.Random.java.
+ */
+static void
+random_setSeed(JSRuntime *rt, int64 seed)
+{
+ int64 tmp;
+
+ JSLL_I2L(tmp, 1000);
+ JSLL_DIV(seed, seed, tmp);
+ JSLL_XOR(tmp, seed, rt->rngMultiplier);
+ JSLL_AND(rt->rngSeed, tmp, rt->rngMask);
+}
+
+static void
+random_init(JSRuntime *rt)
+{
+ int64 tmp, tmp2;
+
+ /* Do at most once. */
+ if (rt->rngInitialized)
+ return;
+ rt->rngInitialized = JS_TRUE;
+
+ /* rt->rngMultiplier = 0x5DEECE66DL */
+ JSLL_ISHL(tmp, 0x5, 32);
+ JSLL_UI2L(tmp2, 0xDEECE66DL);
+ JSLL_OR(rt->rngMultiplier, tmp, tmp2);
+
+ /* rt->rngAddend = 0xBL */
+ JSLL_I2L(rt->rngAddend, 0xBL);
+
+ /* rt->rngMask = (1L << 48) - 1 */
+ JSLL_I2L(tmp, 1);
+ JSLL_SHL(tmp2, tmp, 48);
+ JSLL_SUB(rt->rngMask, tmp2, tmp);
+
+ /* rt->rngDscale = (jsdouble)(1L << 53) */
+ JSLL_SHL(tmp2, tmp, 53);
+ JSLL_L2D(rt->rngDscale, tmp2);
+
+ /* Finally, set the seed from current time. */
+ random_setSeed(rt, PRMJ_Now());
+}
+
+static uint32
+random_next(JSRuntime *rt, int bits)
+{
+ int64 nextseed, tmp;
+ uint32 retval;
+
+ JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier);
+ JSLL_ADD(nextseed, nextseed, rt->rngAddend);
+ JSLL_AND(nextseed, nextseed, rt->rngMask);
+ rt->rngSeed = nextseed;
+ JSLL_USHR(tmp, nextseed, 48 - bits);
+ JSLL_L2I(retval, tmp);
+ return retval;
+}
+
+static jsdouble
+random_nextDouble(JSRuntime *rt)
+{
+ int64 tmp, tmp2;
+ jsdouble d;
+
+ JSLL_ISHL(tmp, random_next(rt, 26), 27);
+ JSLL_UI2L(tmp2, random_next(rt, 27));
+ JSLL_ADD(tmp, tmp, tmp2);
+ JSLL_L2D(d, tmp);
+ return d / rt->rngDscale;
+}
+
+static JSBool
+math_random(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSRuntime *rt;
+ jsdouble z;
+
+ rt = cx->runtime;
+ JS_LOCK_RUNTIME(rt);
+ random_init(rt);
+ z = random_nextDouble(rt);
+ JS_UNLOCK_RUNTIME(rt);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_round(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_copysign(fd_floor(x + 0.5), x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_sin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_sin(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_sqrt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_sqrt(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+static JSBool
+math_tan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x, z;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = fd_tan(x);
+ return js_NewNumberValue(cx, z, rval);
+}
+
+#if JS_HAS_TOSOURCE
+static JSBool
+math_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ *rval = ATOM_KEY(cx->runtime->atomState.MathAtom);
+ return JS_TRUE;
+}
+#endif
+
+static JSFunctionSpec math_static_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, math_toSource, 0, 0, 0},
+#endif
+ {"abs", math_abs, 1, 0, 0},
+ {"acos", math_acos, 1, 0, 0},
+ {"asin", math_asin, 1, 0, 0},
+ {"atan", math_atan, 1, 0, 0},
+ {"atan2", math_atan2, 2, 0, 0},
+ {"ceil", math_ceil, 1, 0, 0},
+ {"cos", math_cos, 1, 0, 0},
+ {"exp", math_exp, 1, 0, 0},
+ {"floor", math_floor, 1, 0, 0},
+ {"log", math_log, 1, 0, 0},
+ {"max", math_max, 2, 0, 0},
+ {"min", math_min, 2, 0, 0},
+ {"pow", math_pow, 2, 0, 0},
+ {"random", math_random, 0, 0, 0},
+ {"round", math_round, 1, 0, 0},
+ {"sin", math_sin, 1, 0, 0},
+ {"sqrt", math_sqrt, 1, 0, 0},
+ {"tan", math_tan, 1, 0, 0},
+ {0,0,0,0,0}
+};
+
+JSObject *
+js_InitMathClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *Math;
+
+ Math = JS_DefineObject(cx, obj, "Math", &math_class, NULL, 0);
+ if (!Math)
+ return NULL;
+ if (!JS_DefineFunctions(cx, Math, math_static_methods))
+ return NULL;
+ if (!JS_DefineConstDoubles(cx, Math, math_constants))
+ return NULL;
+ return Math;
+}
diff --git a/src/dom/js/jsmath.h b/src/dom/js/jsmath.h
new file mode 100644
index 000000000..7a6b21657
--- /dev/null
+++ b/src/dom/js/jsmath.h
@@ -0,0 +1,55 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* -*- Mode: C; tab-width: 8 -*-
+ * Copyright (C) 1998-1999 Netscape Communications Corporation, All Rights Reserved.
+ */
+
+#ifndef jsmath_h___
+#define jsmath_h___
+/*
+ * JS math functions.
+ */
+
+JS_BEGIN_EXTERN_C
+
+extern JSObject *
+js_InitMathClass(JSContext *cx, JSObject *obj);
+
+JS_END_EXTERN_C
+
+#endif /* jsmath_h___ */
diff --git a/src/dom/js/jsnum.c b/src/dom/js/jsnum.c
new file mode 100644
index 000000000..6f6963b69
--- /dev/null
+++ b/src/dom/js/jsnum.c
@@ -0,0 +1,1058 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * IBM Corp.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS number type and wrapper class.
+ */
+#include "jsstddef.h"
+#if defined(XP_WIN) || defined(XP_OS2)
+#include <float.h>
+#endif
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdtoa.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsprf.h"
+#include "jsstr.h"
+
+static JSBool
+num_isNaN(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
+ return JS_TRUE;
+}
+
+static JSBool
+num_isFinite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble x;
+
+ if (!js_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
+ return JS_TRUE;
+}
+
+static JSBool
+num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ jsdouble d;
+ const jschar *bp, *ep;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ /* XXXbe js_strtod shouldn't require NUL termination */
+ bp = js_UndependString(cx, str);
+ if (!bp)
+ return JS_FALSE;
+ if (!js_strtod(cx, bp, &ep, &d))
+ return JS_FALSE;
+ if (ep == bp) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ return JS_TRUE;
+ }
+ return js_NewNumberValue(cx, d, rval);
+}
+
+/* See ECMA 15.1.2.2. */
+static JSBool
+num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ jsint radix;
+ jsdouble d;
+ const jschar *bp, *ep;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+
+ if (argc > 1) {
+ if (!js_ValueToECMAInt32(cx, argv[1], &radix))
+ return JS_FALSE;
+ } else
+ radix = 0;
+
+ if (radix != 0 && (radix < 2 || radix > 36)) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ return JS_TRUE;
+ }
+ /* XXXbe js_strtointeger shouldn't require NUL termination */
+ bp = js_UndependString(cx, str);
+ if (!bp)
+ return JS_FALSE;
+ if (!js_strtointeger(cx, bp, &ep, radix, &d))
+ return JS_FALSE;
+ if (ep == bp) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ return JS_TRUE;
+ }
+ return js_NewNumberValue(cx, d, rval);
+}
+
+const char js_Infinity_str[] = "Infinity";
+const char js_NaN_str[] = "NaN";
+const char js_isNaN_str[] = "isNaN";
+const char js_isFinite_str[] = "isFinite";
+const char js_parseFloat_str[] = "parseFloat";
+const char js_parseInt_str[] = "parseInt";
+
+static JSFunctionSpec number_functions[] = {
+ {"isNaN", num_isNaN, 1,0,0},
+ {"isFinite", num_isFinite, 1,0,0},
+ {"parseFloat", num_parseFloat, 1,0,0},
+ {"parseInt", num_parseInt, 2,0,0},
+ {0,0,0,0,0}
+};
+
+static JSClass number_class = {
+ "Number",
+ JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+static JSBool
+Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsdouble d;
+ jsval v;
+
+ if (argc != 0) {
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ } else {
+ d = 0.0;
+ }
+ if (!js_NewNumberValue(cx, d, &v))
+ return JS_FALSE;
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ *rval = v;
+ return JS_TRUE;
+ }
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
+ return JS_TRUE;
+}
+
+#if JS_HAS_TOSOURCE
+static JSBool
+num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+ jsdouble d;
+ char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
+ char buf[64];
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &number_class, argv))
+ return JS_FALSE;
+ v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ JS_ASSERT(JSVAL_IS_NUMBER(v));
+ d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
+ numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
+ if (!numStr) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ JS_snprintf(buf, sizeof buf, "(new %s(%s))", number_class.name, numStr);
+ str = JS_NewStringCopyZ(cx, buf);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif
+
+/* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
+static char *
+IntToString(jsint i, char *buf, size_t bufSize)
+{
+ char *cp;
+ jsuint u;
+
+ u = (i < 0) ? -i : i;
+
+ cp = buf + bufSize; /* one past last buffer cell */
+ *--cp = '\0'; /* null terminate the string to be */
+
+ /*
+ * Build the string from behind. We use multiply and subtraction
+ * instead of modulus because that's much faster.
+ */
+ do {
+ jsuint newu = u / 10;
+ *--cp = (char)(u - newu * 10) + '0';
+ u = newu;
+ } while (u != 0);
+
+ if (i < 0)
+ *--cp = '-';
+
+ return cp;
+}
+
+static JSBool
+num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+ jsdouble d;
+ jsint base;
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &number_class, argv))
+ return JS_FALSE;
+ v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ JS_ASSERT(JSVAL_IS_NUMBER(v));
+ d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
+ base = 10;
+ if (argc != 0) {
+ if (!js_ValueToECMAInt32(cx, argv[0], &base))
+ return JS_FALSE;
+ if (base < 2 || base > 36) {
+ char numBuf[12];
+ char *numStr = IntToString(base, numBuf, sizeof numBuf);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
+ numStr);
+ return JS_FALSE;
+ }
+ }
+ if (base == 10)
+ str = js_NumberToString(cx, d);
+ else {
+ char *dStr = JS_dtobasestr(base, d);
+ if (!dStr) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ str = JS_NewStringCopyZ(cx, dStr);
+ free(dStr);
+ }
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+/*
+ * For now, forcibly ignore the first (or any) argument and return toString().
+ * ECMA allows this, although it doesn't 'encourage it'.
+ * [The first argument is being reserved by ECMA and we don't want it confused
+ * with a radix]
+ */
+ return num_toString(cx, obj, 0, argv, rval);
+}
+
+static JSBool
+num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (!JS_InstanceOf(cx, obj, &number_class, argv))
+ return JS_FALSE;
+ *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ return JS_TRUE;
+}
+
+
+#if JS_HAS_NUMBER_FORMATS
+#define MAX_PRECISION 100
+
+static JSBool
+num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDToStrMode zeroArgMode,
+ JSDToStrMode oneArgMode, jsint precisionMin, jsint precisionMax, jsint precisionOffset)
+{
+ jsval v;
+ jsdouble d, precision;
+ JSString *str;
+ char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */
+
+ if (!JS_InstanceOf(cx, obj, &number_class, argv))
+ return JS_FALSE;
+ v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ JS_ASSERT(JSVAL_IS_NUMBER(v));
+ d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
+
+ if (JSVAL_IS_VOID(argv[0])) {
+ precision = 0.0;
+ oneArgMode = zeroArgMode;
+ } else {
+ if (!js_ValueToNumber(cx, argv[0], &precision))
+ return JS_FALSE;
+ precision = js_DoubleToInteger(precision);
+ if (precision < precisionMin || precision > precisionMax) {
+ numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
+ if (!numStr)
+ JS_ReportOutOfMemory(cx);
+ else
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
+ return JS_FALSE;
+ }
+ }
+
+ numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
+ if (!numStr) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ str = JS_NewStringCopyZ(cx, numStr);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+num_toFixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
+ return num_to(cx, obj, argc, argv, rval, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0);
+}
+
+static JSBool
+num_toExponential(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
+ return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1);
+}
+
+static JSBool
+num_toPrecision(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
+ return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0);
+}
+#endif /* JS_HAS_NUMBER_FORMATS */
+
+
+static JSFunctionSpec number_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, num_toSource, 0,0,0},
+#endif
+ {js_toString_str, num_toString, 0,0,0},
+ {js_toLocaleString_str, num_toLocaleString, 0,0,0},
+ {js_valueOf_str, num_valueOf, 0,0,0},
+#if JS_HAS_NUMBER_FORMATS
+ {"toFixed", num_toFixed, 1,0,0},
+ {"toExponential", num_toExponential, 1,0,0},
+ {"toPrecision", num_toPrecision, 1,0,0},
+#endif
+ {0,0,0,0,0}
+};
+
+/* NB: Keep this in synch with number_constants[]. */
+enum nc_slot {
+ NC_NaN,
+ NC_POSITIVE_INFINITY,
+ NC_NEGATIVE_INFINITY,
+ NC_MAX_VALUE,
+ NC_MIN_VALUE,
+ NC_LIMIT
+};
+
+/*
+ * Some to most C compilers forbid spelling these at compile time, or barf
+ * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
+ * using union jsdpun.
+ */
+static JSConstDoubleSpec number_constants[] = {
+ {0, js_NaN_str, 0,{0,0,0}},
+ {0, "POSITIVE_INFINITY", 0,{0,0,0}},
+ {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
+ {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
+ {0, "MIN_VALUE", 0,{0,0,0}},
+ {0,0,0,{0,0,0}}
+};
+
+static jsdouble NaN;
+
+
+#if defined XP_WIN && \
+ !defined __MWERKS__ && \
+ (defined _M_IX86 || \
+ (defined __GNUC__ && !defined __MINGW32__))
+
+/*
+ * Set the exception mask to mask all exceptions and set the FPU precision
+ * to 53 bit mantissa.
+ * On Alpha platform this is handled via Compiler option.
+ */
+#define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC)
+
+#else
+
+#define FIX_FPU() ((void)0)
+
+#endif
+
+JSBool
+js_InitRuntimeNumberState(JSContext *cx)
+{
+ JSRuntime *rt;
+ jsdpun u;
+
+ rt = cx->runtime;
+ JS_ASSERT(!rt->jsNaN);
+
+ FIX_FPU();
+
+ u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
+ u.s.lo = 0xffffffff;
+ number_constants[NC_NaN].dval = NaN = u.d;
+ rt->jsNaN = js_NewDouble(cx, NaN);
+ if (!rt->jsNaN || !js_LockGCThing(cx, rt->jsNaN))
+ return JS_FALSE;
+
+ u.s.hi = JSDOUBLE_HI32_EXPMASK;
+ u.s.lo = 0x00000000;
+ number_constants[NC_POSITIVE_INFINITY].dval = u.d;
+ rt->jsPositiveInfinity = js_NewDouble(cx, u.d);
+ if (!rt->jsPositiveInfinity ||
+ !js_LockGCThing(cx, rt->jsPositiveInfinity)) {
+ return JS_FALSE;
+ }
+
+ u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
+ u.s.lo = 0x00000000;
+ number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
+ rt->jsNegativeInfinity = js_NewDouble(cx, u.d);
+ if (!rt->jsNegativeInfinity ||
+ !js_LockGCThing(cx, rt->jsNegativeInfinity)) {
+ return JS_FALSE;
+ }
+
+ u.s.hi = 0;
+ u.s.lo = 1;
+ number_constants[NC_MIN_VALUE].dval = u.d;
+
+ return JS_TRUE;
+}
+
+void
+js_FinishRuntimeNumberState(JSContext *cx)
+{
+ JSRuntime *rt = cx->runtime;
+
+ js_UnlockGCThingRT(rt, rt->jsNaN);
+ js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
+ js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
+
+ rt->jsNaN = NULL;
+ rt->jsNegativeInfinity = NULL;
+ rt->jsPositiveInfinity = NULL;
+}
+
+JSObject *
+js_InitNumberClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto, *ctor;
+ JSRuntime *rt;
+
+ /* XXX must do at least once per new thread, so do it per JSContext... */
+ FIX_FPU();
+
+ if (!JS_DefineFunctions(cx, obj, number_functions))
+ return NULL;
+
+ proto = JS_InitClass(cx, obj, NULL, &number_class, Number, 1,
+ NULL, number_methods, NULL, NULL);
+ if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
+ return NULL;
+ OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE, JSVAL_ZERO);
+ if (!JS_DefineConstDoubles(cx, ctor, number_constants))
+ return NULL;
+
+ /* ECMA 15.1.1.1 */
+ rt = cx->runtime;
+ if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
+ NULL, NULL, JSPROP_PERMANENT)) {
+ return NULL;
+ }
+
+ /* ECMA 15.1.1.2 */
+ if (!JS_DefineProperty(cx, obj, js_Infinity_str,
+ DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
+ NULL, NULL, JSPROP_PERMANENT)) {
+ return NULL;
+ }
+ return proto;
+}
+
+jsdouble *
+js_NewDouble(JSContext *cx, jsdouble d)
+{
+ jsdouble *dp;
+
+ dp = (jsdouble *) js_AllocGCThing(cx, GCX_DOUBLE);
+ if (!dp)
+ return NULL;
+ *dp = d;
+ return dp;
+}
+
+void
+js_FinalizeDouble(JSContext *cx, jsdouble *dp)
+{
+ *dp = NaN;
+}
+
+JSBool
+js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
+{
+ jsdouble *dp;
+
+ dp = js_NewDouble(cx, d);
+ if (!dp)
+ return JS_FALSE;
+ *rval = DOUBLE_TO_JSVAL(dp);
+ return JS_TRUE;
+}
+
+JSBool
+js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
+{
+ jsint i;
+ JSBool ok;
+
+ SET_FPU();
+
+ if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
+ *rval = INT_TO_JSVAL(i);
+ ok = JS_TRUE;
+ } else {
+ ok = js_NewDoubleValue(cx, d, rval);
+ }
+
+ RESTORE_FPU();
+ return ok;
+}
+
+JSObject *
+js_NumberToObject(JSContext *cx, jsdouble d)
+{
+ JSObject *obj;
+ jsval v;
+
+ obj = js_NewObject(cx, &number_class, NULL, NULL);
+ if (!obj)
+ return NULL;
+ if (!js_NewNumberValue(cx, d, &v)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
+ return obj;
+}
+
+JSString *
+js_NumberToString(JSContext *cx, jsdouble d)
+{
+ jsint i;
+ char buf[DTOSTR_STANDARD_BUFFER_SIZE];
+ char *numStr;
+
+ if (JSDOUBLE_IS_INT(d, i))
+ numStr = IntToString(i, buf, sizeof buf);
+ else {
+ numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d);
+ if (!numStr) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ }
+ return JS_NewStringCopyZ(cx, numStr);
+}
+
+JSBool
+js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
+{
+ JSObject *obj;
+ JSString *str;
+ const jschar *bp, *ep;
+
+ if (JSVAL_IS_OBJECT(v)) {
+ obj = JSVAL_TO_OBJECT(v);
+ if (!obj) {
+ *dp = 0;
+ return JS_TRUE;
+ }
+ if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &v))
+ return JS_FALSE;
+ }
+ if (JSVAL_IS_INT(v)) {
+ *dp = (jsdouble)JSVAL_TO_INT(v);
+ } else if (JSVAL_IS_DOUBLE(v)) {
+ *dp = *JSVAL_TO_DOUBLE(v);
+ } else if (JSVAL_IS_STRING(v)) {
+ str = JSVAL_TO_STRING(v);
+ /*
+ * Note that ECMA doesn't treat a string beginning with a '0' as an
+ * octal number here. This works because all such numbers will be
+ * interpreted as decimal by js_strtod and will never get passed to
+ * js_strtointeger (which would interpret them as octal).
+ */
+ /* XXXbe js_strtod shouldn't require NUL termination */
+ bp = js_UndependString(cx, str);
+ if (!bp)
+ return JS_FALSE;
+ if ((!js_strtod(cx, bp, &ep, dp) ||
+ js_SkipWhiteSpace(ep) != bp + str->length) &&
+ (!js_strtointeger(cx, bp, &ep, 0, dp) ||
+ js_SkipWhiteSpace(ep) != bp + str->length)) {
+ goto badstr;
+ }
+ } else if (JSVAL_IS_BOOLEAN(v)) {
+ *dp = JSVAL_TO_BOOLEAN(v) ? 1 : 0;
+ } else {
+#if JS_BUG_FALLIBLE_TONUM
+ str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
+badstr:
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NAN,
+ JS_GetStringBytes(str));
+
+ }
+ return JS_FALSE;
+#else
+badstr:
+ *dp = *cx->runtime->jsNaN;
+#endif
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
+{
+ jsdouble d;
+
+ if (!js_ValueToNumber(cx, v, &d))
+ return JS_FALSE;
+ return js_DoubleToECMAInt32(cx, d, ip);
+}
+
+JSBool
+js_DoubleToECMAInt32(JSContext *cx, jsdouble d, int32 *ip)
+{
+ jsdouble two32 = 4294967296.0;
+ jsdouble two31 = 2147483648.0;
+
+ if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
+ *ip = 0;
+ return JS_TRUE;
+ }
+ d = fmod(d, two32);
+ d = (d >= 0) ? floor(d) : ceil(d) + two32;
+ if (d >= two31)
+ *ip = (int32)(d - two32);
+ else
+ *ip = (int32)d;
+ return JS_TRUE;
+}
+
+JSBool
+js_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
+{
+ jsdouble d;
+
+ if (!js_ValueToNumber(cx, v, &d))
+ return JS_FALSE;
+ return js_DoubleToECMAUint32(cx, d, ip);
+}
+
+JSBool
+js_DoubleToECMAUint32(JSContext *cx, jsdouble d, uint32 *ip)
+{
+ JSBool neg;
+ jsdouble two32 = 4294967296.0;
+
+ if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
+ *ip = 0;
+ return JS_TRUE;
+ }
+
+ neg = (d < 0);
+ d = floor(neg ? -d : d);
+ d = neg ? -d : d;
+
+ d = fmod(d, two32);
+
+ d = (d >= 0) ? d : d + two32;
+ *ip = (uint32)d;
+ return JS_TRUE;
+}
+
+JSBool
+js_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
+{
+ jsdouble d;
+ JSString *str;
+
+ if (JSVAL_IS_INT(v)) {
+ *ip = JSVAL_TO_INT(v);
+ return JS_TRUE;
+ }
+ if (!js_ValueToNumber(cx, v, &d))
+ return JS_FALSE;
+ if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
+ str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_CONVERT, JS_GetStringBytes(str));
+
+ }
+ return JS_FALSE;
+ }
+ *ip = (int32)floor(d + 0.5); /* Round to nearest */
+ return JS_TRUE;
+}
+
+JSBool
+js_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
+{
+ jsdouble d;
+ jsuint i, m;
+ JSBool neg;
+
+ if (!js_ValueToNumber(cx, v, &d))
+ return JS_FALSE;
+ if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
+ *ip = 0;
+ return JS_TRUE;
+ }
+ i = (jsuint)d;
+ if ((jsdouble)i == d) {
+ *ip = (uint16)i;
+ return JS_TRUE;
+ }
+ neg = (d < 0);
+ d = floor(neg ? -d : d);
+ d = neg ? -d : d;
+ m = JS_BIT(16);
+ d = fmod(d, (double)m);
+ if (d < 0)
+ d += m;
+ *ip = (uint16) d;
+ return JS_TRUE;
+}
+
+jsdouble
+js_DoubleToInteger(jsdouble d)
+{
+ JSBool neg;
+
+ if (d == 0)
+ return d;
+ if (!JSDOUBLE_IS_FINITE(d)) {
+ if (JSDOUBLE_IS_NaN(d))
+ return 0;
+ return d;
+ }
+ neg = (d < 0);
+ d = floor(neg ? -d : d);
+ return neg ? -d : d;
+}
+
+
+JSBool
+js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp)
+{
+ char cbuf[32];
+ size_t i;
+ char *cstr, *istr, *estr;
+ JSBool negative;
+ jsdouble d;
+ const jschar *s1 = js_SkipWhiteSpace(s);
+ size_t length = js_strlen(s1);
+
+ /* Use cbuf to avoid malloc */
+ if (length >= sizeof cbuf) {
+ cstr = (char *) JS_malloc(cx, length + 1);
+ if (!cstr)
+ return JS_FALSE;
+ } else {
+ cstr = cbuf;
+ }
+
+ for (i = 0; i <= length; i++) {
+ if (s1[i] >> 8) {
+ cstr[i] = 0;
+ break;
+ }
+ cstr[i] = (char)s1[i];
+ }
+
+ istr = cstr;
+ if ((negative = (*istr == '-')) != 0 || *istr == '+')
+ istr++;
+ if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
+ d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
+ estr = istr + 8;
+ } else {
+ int err;
+ d = JS_strtod(cstr, &estr, &err);
+ if (err == JS_DTOA_ENOMEM) {
+ JS_ReportOutOfMemory(cx);
+ if (cstr != cbuf)
+ JS_free(cx, cstr);
+ return JS_FALSE;
+ }
+ if (err == JS_DTOA_ERANGE) {
+ if (d == HUGE_VAL)
+ d = *cx->runtime->jsPositiveInfinity;
+ else if (d == -HUGE_VAL)
+ d = *cx->runtime->jsNegativeInfinity;
+ }
+#ifdef HPUX
+ if (d == 0.0 && negative) {
+ /*
+ * "-0", "-1e-2000" come out as positive zero
+ * here on HPUX. Force a negative zero instead.
+ */
+ JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT;
+ JSDOUBLE_LO32(d) = 0;
+ }
+#endif
+ }
+
+ i = estr - cstr;
+ if (cstr != cbuf)
+ JS_free(cx, cstr);
+ *ep = i ? s1 + i : s;
+ *dp = d;
+ return JS_TRUE;
+}
+
+struct BinaryDigitReader
+{
+ uintN base; /* Base of number; must be a power of 2 */
+ uintN digit; /* Current digit value in radix given by base */
+ uintN digitMask; /* Mask to extract the next bit from digit */
+ const jschar *digits; /* Pointer to the remaining digits */
+ const jschar *end; /* Pointer to first non-digit */
+};
+
+/* Return the next binary digit from the number or -1 if done */
+static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr)
+{
+ intN bit;
+
+ if (bdr->digitMask == 0) {
+ uintN c;
+
+ if (bdr->digits == bdr->end)
+ return -1;
+
+ c = *bdr->digits++;
+ if ('0' <= c && c <= '9')
+ bdr->digit = c - '0';
+ else if ('a' <= c && c <= 'z')
+ bdr->digit = c - 'a' + 10;
+ else bdr->digit = c - 'A' + 10;
+ bdr->digitMask = bdr->base >> 1;
+ }
+ bit = (bdr->digit & bdr->digitMask) != 0;
+ bdr->digitMask >>= 1;
+ return bit;
+}
+
+JSBool
+js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, jsdouble *dp)
+{
+ JSBool negative;
+ jsdouble value;
+ const jschar *start;
+ const jschar *s1 = js_SkipWhiteSpace(s);
+
+ if ((negative = (*s1 == '-')) != 0 || *s1 == '+')
+ s1++;
+
+ if (base == 0) {
+ /* No base supplied, or some base that evaluated to 0. */
+ if (*s1 == '0') {
+ /* It's either hex or octal; only increment char if str isn't '0' */
+ if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */
+ s1 += 2;
+ base = 16;
+ } else { /* Octal */
+ base = 8;
+ }
+ } else {
+ base = 10; /* Default to decimal. */
+ }
+ } else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) {
+ /* If base is 16, ignore hex prefix. */
+ s1 += 2;
+ }
+
+ /*
+ * Done with the preliminaries; find some prefix of the string that's
+ * a number in the given base.
+ */
+ start = s1; /* Mark - if string is empty, we return NaN. */
+ value = 0.0;
+ for (;;) {
+ uintN digit;
+ jschar c = *s1;
+ if ('0' <= c && c <= '9')
+ digit = c - '0';
+ else if ('a' <= c && c <= 'z')
+ digit = c - 'a' + 10;
+ else if ('A' <= c && c <= 'Z')
+ digit = c - 'A' + 10;
+ else
+ break;
+ if (digit >= (uintN)base)
+ break;
+ value = value * base + digit;
+ s1++;
+ }
+
+ if (value >= 9007199254740992.0) {
+ if (base == 10) {
+ /*
+ * If we're accumulating a decimal number and the number is >=
+ * 2^53, then the result from the repeated multiply-add above may
+ * be inaccurate. Call JS_strtod to get the correct answer.
+ */
+ size_t i;
+ size_t length = s1 - start;
+ char *cstr = (char *) JS_malloc(cx, length + 1);
+ char *estr;
+ int err=0;
+
+ if (!cstr)
+ return JS_FALSE;
+ for (i = 0; i != length; i++)
+ cstr[i] = (char)start[i];
+ cstr[length] = 0;
+
+ value = JS_strtod(cstr, &estr, &err);
+ if (err == JS_DTOA_ENOMEM) {
+ JS_ReportOutOfMemory(cx);
+ JS_free(cx, cstr);
+ return JS_FALSE;
+ }
+ if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
+ value = *cx->runtime->jsPositiveInfinity;
+ JS_free(cx, cstr);
+ } else if ((base & (base - 1)) == 0) {
+ /*
+ * The number may also be inaccurate for power-of-two bases. This
+ * happens if the addition in value * base + digit causes a round-
+ * down to an even least significant mantissa bit when the first
+ * dropped bit is a one. If any of the following digits in the
+ * number (which haven't been added in yet) are nonzero, then the
+ * correct action would have been to round up instead of down. An
+ * example occurs when reading the number 0x1000000000000081, which
+ * rounds to 0x1000000000000000 instead of 0x1000000000000100.
+ */
+ struct BinaryDigitReader bdr;
+ intN bit, bit2;
+ intN j;
+
+ bdr.base = base;
+ bdr.digitMask = 0;
+ bdr.digits = start;
+ bdr.end = s1;
+ value = 0.0;
+
+ /* Skip leading zeros. */
+ do {
+ bit = GetNextBinaryDigit(&bdr);
+ } while (bit == 0);
+
+ if (bit == 1) {
+ /* Gather the 53 significant bits (including the leading 1) */
+ value = 1.0;
+ for (j = 52; j; j--) {
+ bit = GetNextBinaryDigit(&bdr);
+ if (bit < 0)
+ goto done;
+ value = value*2 + bit;
+ }
+ /* bit2 is the 54th bit (the first dropped from the mantissa) */
+ bit2 = GetNextBinaryDigit(&bdr);
+ if (bit2 >= 0) {
+ jsdouble factor = 2.0;
+ intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
+ intN bit3;
+
+ while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
+ sticky |= bit3;
+ factor *= 2;
+ }
+ value += bit2 & (bit | sticky);
+ value *= factor;
+ }
+ done:;
+ }
+ }
+ }
+ /* We don't worry about inaccurate numbers for any other base. */
+
+ if (s1 == start) {
+ *dp = 0.0;
+ *ep = s;
+ } else {
+ *dp = negative ? -value : value;
+ *ep = s1;
+ }
+ return JS_TRUE;
+}
diff --git a/src/dom/js/jsnum.h b/src/dom/js/jsnum.h
new file mode 100644
index 000000000..46992e2b6
--- /dev/null
+++ b/src/dom/js/jsnum.h
@@ -0,0 +1,280 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsnum_h___
+#define jsnum_h___
+/*
+ * JS number (IEEE double) interface.
+ *
+ * JS numbers are optimistically stored in the top 31 bits of 32-bit integers,
+ * but floating point literals, results that overflow 31 bits, and division and
+ * modulus operands and results require a 64-bit IEEE double. These are GC'ed
+ * and pointed to by 32-bit jsvals on the stack and in object properties.
+ *
+ * When a JS number is treated as an object (followed by . or []), the runtime
+ * wraps it with a JSObject whose valueOf method returns the unwrapped number.
+ */
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * Stefan Hanske <sh990154@mail.uni-greifswald.de> reports:
+ * ARM is a little endian architecture but 64 bit double words are stored
+ * differently: the 32 bit words are in little endian byte order, the two words
+ * are stored in big endian`s way.
+ */
+
+#if defined(__arm) || defined(__arm32__) || defined(__arm26__) || defined(__arm__)
+#define CPU_IS_ARM
+#endif
+
+typedef union jsdpun {
+ struct {
+#if defined(IS_LITTLE_ENDIAN) && !defined(CPU_IS_ARM)
+ uint32 lo, hi;
+#else
+ uint32 hi, lo;
+#endif
+ } s;
+ jsdouble d;
+} jsdpun;
+
+#if (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || __GNUC__ > 2
+/*
+ * This version of the macros is safe for the alias optimizations that gcc
+ * does, but uses gcc-specific extensions.
+ */
+
+#define JSDOUBLE_HI32(x) (__extension__ ({ jsdpun u; u.d = (x); u.s.hi; }))
+#define JSDOUBLE_LO32(x) (__extension__ ({ jsdpun u; u.d = (x); u.s.lo; }))
+#define JSDOUBLE_SET_HI32(x, y) \
+ (__extension__ ({ jsdpun u; u.d = (x); u.s.hi = (y); (x) = u.d; }))
+#define JSDOUBLE_SET_LO32(x, y) \
+ (__extension__ ({ jsdpun u; u.d = (x); u.s.lo = (y); (x) = u.d; }))
+
+#else /* not or old GNUC */
+
+/*
+ * We don't know of any non-gcc compilers that perform alias optimization,
+ * so this code should work.
+ */
+
+#if defined(IS_LITTLE_ENDIAN) && !defined(CPU_IS_ARM)
+#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
+#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
+#else
+#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
+#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
+#endif
+
+#define JSDOUBLE_SET_HI32(x, y) (JSDOUBLE_HI32(x)=(y))
+#define JSDOUBLE_SET_LO32(x, y) (JSDOUBLE_LO32(x)=(y))
+
+#endif /* not or old GNUC */
+
+#define JSDOUBLE_HI32_SIGNBIT 0x80000000
+#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
+#define JSDOUBLE_HI32_MANTMASK 0x000fffff
+
+#define JSDOUBLE_IS_NaN(x) \
+ ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
+ (JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
+
+#define JSDOUBLE_IS_INFINITE(x) \
+ ((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
+ !JSDOUBLE_LO32(x))
+
+#define JSDOUBLE_IS_FINITE(x) \
+ ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK)
+
+#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \
+ JSDOUBLE_LO32(d) == 0)
+
+/*
+ * JSDOUBLE_IS_INT first checks that d is neither NaN nor infinite, to avoid
+ * raising SIGFPE on platforms such as Alpha Linux, then (only if the cast is
+ * safe) leaves i as (jsint)d. This also avoid anomalous NaN floating point
+ * comparisons under MSVC.
+ */
+#define JSDOUBLE_IS_INT(d, i) (JSDOUBLE_IS_FINITE(d) \
+ && !JSDOUBLE_IS_NEGZERO(d) \
+ && ((d) == (i = (jsint)(d))))
+
+/* Initialize number constants and runtime state for the first context. */
+extern JSBool
+js_InitRuntimeNumberState(JSContext *cx);
+
+extern void
+js_FinishRuntimeNumberState(JSContext *cx);
+
+/* Initialize the Number class, returning its prototype object. */
+extern JSObject *
+js_InitNumberClass(JSContext *cx, JSObject *obj);
+
+/*
+ * String constants for global function names, used in jsapi.c and jsnum.c.
+ */
+extern const char js_Infinity_str[];
+extern const char js_NaN_str[];
+extern const char js_isNaN_str[];
+extern const char js_isFinite_str[];
+extern const char js_parseFloat_str[];
+extern const char js_parseInt_str[];
+
+/* GC-allocate a new JS number. */
+extern jsdouble *
+js_NewDouble(JSContext *cx, jsdouble d);
+
+extern void
+js_FinalizeDouble(JSContext *cx, jsdouble *dp);
+
+extern JSBool
+js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval);
+
+extern JSBool
+js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval);
+
+/* Construct a Number instance that wraps around d. */
+extern JSObject *
+js_NumberToObject(JSContext *cx, jsdouble d);
+
+/* Convert a number to a GC'ed string. */
+extern JSString *
+js_NumberToString(JSContext *cx, jsdouble d);
+
+/*
+ * Convert a value to a number, returning false after reporting any error,
+ * otherwise returning true with *dp set.
+ */
+extern JSBool
+js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp);
+
+/*
+ * Convert a value or a double to an int32, according to the ECMA rules
+ * for ToInt32.
+ */
+extern JSBool
+js_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip);
+
+extern JSBool
+js_DoubleToECMAInt32(JSContext *cx, jsdouble d, int32 *ip);
+
+/*
+ * Convert a value or a double to a uint32, according to the ECMA rules
+ * for ToUint32.
+ */
+extern JSBool
+js_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip);
+
+extern JSBool
+js_DoubleToECMAUint32(JSContext *cx, jsdouble d, uint32 *ip);
+
+/*
+ * Convert a value to a number, then to an int32 if it fits by rounding to
+ * nearest; but failing with an error report if the double is out of range
+ * or unordered.
+ */
+extern JSBool
+js_ValueToInt32(JSContext *cx, jsval v, int32 *ip);
+
+/*
+ * Convert a value to a number, then to a uint16 according to the ECMA rules
+ * for ToUint16.
+ */
+extern JSBool
+js_ValueToUint16(JSContext *cx, jsval v, uint16 *ip);
+
+/*
+ * Convert a jsdouble to an integral number, stored in a jsdouble.
+ * If d is NaN, return 0. If d is an infinity, return it without conversion.
+ */
+extern jsdouble
+js_DoubleToInteger(jsdouble d);
+
+/*
+ * Similar to strtod except that it replaces overflows with infinities of the
+ * correct sign, and underflows with zeros of the correct sign. Guaranteed to
+ * return the closest double number to the given input in dp.
+ *
+ * Also allows inputs of the form [+|-]Infinity, which produce an infinity of
+ * the appropriate sign. The case of the "Infinity" string must match exactly.
+ * If the string does not contain a number, set *ep to s and return 0.0 in dp.
+ * Return false if out of memory.
+ */
+extern JSBool
+js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp);
+
+/*
+ * Similar to strtol except that it handles integers of arbitrary size.
+ * Guaranteed to return the closest double number to the given input when radix
+ * is 10 or a power of 2. Callers may see round-off errors for very large
+ * numbers of a different radix than 10 or a power of 2.
+ *
+ * If the string does not contain a number, set *ep to s and return 0.0 in dp.
+ * Return false if out of memory.
+ */
+extern JSBool
+js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint radix, jsdouble *dp);
+
+
+#ifdef XP_OS2
+/* XXX see bug 224487
+ * On OS/2, some system function calls seem to change the FPU control word,
+ * such that we crash with a floating underflow exception. The FIX_FPU() call
+ * in jsnum.c does not always work, as sometimes FIX_FPU() is called BEFORE the
+ * OS/2 system call that horks the FPU control word. So, on OS/2, we need to do
+ * what the comment at the top of this file (around line 80) suggests: setting
+ * the FPU precision (& exceptions mask) before calling strtod or dtoa. Also,
+ * we play nice by reverting to the previous FPU control word at the end of
+ * those functions.
+ *
+ * Set the exception mask to mask all exceptions and set the FPU precision
+ * to 53 bit mantissa.
+ */
+ #define SET_FPU() unsigned cw = _control87(0,0); \
+ _control87((CW_DEFAULT & ~MCW_PC) | PC_53, 0xffff)
+ #define RESTORE_FPU() _control87(cw, MCW_EM | MCW_IC | MCW_RC | MCW_PC)
+#else
+ #define SET_FPU() ((void)0)
+ #define RESTORE_FPU() ((void)0)
+#endif
+
+JS_END_EXTERN_C
+
+#endif /* jsnum_h___ */
diff --git a/src/dom/js/jsobj.c b/src/dom/js/jsobj.c
new file mode 100644
index 000000000..1da1f138b
--- /dev/null
+++ b/src/dom/js/jsobj.c
@@ -0,0 +1,3900 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS object implementation.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jshash.h" /* Added by JSIFY */
+#include "jsdhash.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+#include "jsopcode.h"
+
+#include "jsdbgapi.h" /* whether or not JS_HAS_OBJ_WATCHPOINT */
+
+#ifdef JS_THREADSAFE
+#define NATIVE_DROP_PROPERTY js_DropProperty
+
+extern void
+js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop);
+#else
+#define NATIVE_DROP_PROPERTY NULL
+#endif
+
+#ifdef XP_MAC
+#pragma export on
+#endif
+
+JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
+ js_NewObjectMap, js_DestroyObjectMap,
+#if defined JS_THREADSAFE && defined DEBUG
+ _js_LookupProperty, js_DefineProperty,
+#else
+ js_LookupProperty, js_DefineProperty,
+#endif
+ js_GetProperty, js_SetProperty,
+ js_GetAttributes, js_SetAttributes,
+ js_DeleteProperty, js_DefaultValue,
+ js_Enumerate, js_CheckAccess,
+ NULL, NATIVE_DROP_PROPERTY,
+ js_Call, js_Construct,
+ NULL, js_HasInstance,
+ js_SetProtoOrParent, js_SetProtoOrParent,
+ js_Mark, js_Clear,
+ js_GetRequiredSlot, js_SetRequiredSlot
+};
+
+#ifdef XP_MAC
+#pragma export off
+#endif
+
+JSClass js_ObjectClass = {
+ js_Object_str,
+ 0,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+#if JS_HAS_OBJ_PROTO_PROP
+
+static JSBool
+obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+static JSBool
+obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+static JSBool
+obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+
+static JSPropertySpec object_props[] = {
+ /* These two must come first; see object_props[slot].name usage below. */
+ {js_proto_str, JSSLOT_PROTO, JSPROP_PERMANENT|JSPROP_SHARED,
+ obj_getSlot, obj_setSlot},
+ {js_parent_str,JSSLOT_PARENT,JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED,
+ obj_getSlot, obj_setSlot},
+ {js_count_str, 0, JSPROP_PERMANENT,obj_getCount, obj_getCount},
+ {0,0,0,0,0}
+};
+
+/* NB: JSSLOT_PROTO and JSSLOT_PARENT are already indexes into object_props. */
+#define JSSLOT_COUNT 2
+
+static JSBool
+ReportStrictSlot(JSContext *cx, uint32 slot)
+{
+ if (slot == JSSLOT_PROTO)
+ return JS_TRUE;
+ return JS_ReportErrorFlagsAndNumber(cx,
+ JSREPORT_WARNING | JSREPORT_STRICT,
+ js_GetErrorMessage, NULL,
+ JSMSG_DEPRECATED_USAGE,
+ object_props[slot].name);
+}
+
+static JSBool
+obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ uint32 slot;
+ JSAccessMode mode;
+ uintN attrs;
+
+ slot = (uint32) JSVAL_TO_INT(id);
+ if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, slot))
+ return JS_FALSE;
+ if (id == INT_TO_JSVAL(JSSLOT_PROTO)) {
+ id = (jsid)cx->runtime->atomState.protoAtom;
+ mode = JSACC_PROTO;
+ } else {
+ id = (jsid)cx->runtime->atomState.parentAtom;
+ mode = JSACC_PARENT;
+ }
+ if (!OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, &attrs))
+ return JS_FALSE;
+ *vp = OBJ_GET_SLOT(cx, obj, slot);
+ return JS_TRUE;
+}
+
+static JSBool
+obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSObject *pobj;
+ uint32 slot;
+ uintN attrs;
+
+ if (!JSVAL_IS_OBJECT(*vp))
+ return JS_TRUE;
+ pobj = JSVAL_TO_OBJECT(*vp);
+ slot = (uint32) JSVAL_TO_INT(id);
+ if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, slot))
+ return JS_FALSE;
+
+ /* __parent__ is readonly and permanent, only __proto__ may be set. */
+ if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_PROTO | JSACC_WRITE, vp, &attrs))
+ return JS_FALSE;
+
+ return js_SetProtoOrParent(cx, obj, slot, pobj);
+}
+
+static JSBool
+obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsval iter_state;
+ jsid num_properties;
+ JSBool ok;
+
+ if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT))
+ return JS_FALSE;
+
+ /* Get the number of properties to enumerate. */
+ iter_state = JSVAL_NULL;
+ ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties);
+ if (!ok)
+ goto out;
+
+ if (!JSVAL_IS_INT(num_properties)) {
+ JS_ASSERT(0);
+ *vp = JSVAL_ZERO;
+ goto out;
+ }
+ *vp = num_properties;
+
+out:
+ if (iter_state != JSVAL_NULL)
+ ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
+ return ok;
+}
+
+#else /* !JS_HAS_OBJ_PROTO_PROP */
+
+#define object_props NULL
+
+#endif /* !JS_HAS_OBJ_PROTO_PROP */
+
+JSBool
+js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj)
+{
+ JSRuntime *rt;
+ JSObject *obj2, *oldproto;
+ JSScope *scope, *newscope;
+
+ /*
+ * Serialize all proto and parent setting in order to detect cycles.
+ * We nest locks in this function, and only here, in the following orders:
+ *
+ * (1) rt->setSlotLock < pobj's scope lock;
+ * rt->setSlotLock < pobj's proto-or-parent's scope lock;
+ * rt->setSlotLock < pobj's grand-proto-or-parent's scope lock;
+ * etc...
+ * (2) rt->setSlotLock < obj's scope lock < pobj's scope lock.
+ *
+ * We avoid AB-BA deadlock by restricting obj from being on pobj's parent
+ * or proto chain (pobj may already be on obj's parent or proto chain; it
+ * could be moving up or down). We finally order obj with respect to pobj
+ * at the bottom of this routine (just before releasing rt->setSlotLock),
+ * by making pobj be obj's prototype or parent.
+ *
+ * After we have set the slot and released rt->setSlotLock, another call
+ * to js_SetProtoOrParent could nest locks according to the first order
+ * list above, but it cannot deadlock with any other thread. For there
+ * to be a deadlock, other parts of the engine would have to nest scope
+ * locks in the opposite order. XXXbe ensure they don't!
+ */
+ rt = cx->runtime;
+#ifdef JS_THREADSAFE
+
+ JS_ACQUIRE_LOCK(rt->setSlotLock);
+ while (rt->setSlotBusy) {
+ jsrefcount saveDepth;
+
+ /* Take pains to avoid nesting rt->gcLock inside rt->setSlotLock! */
+ JS_RELEASE_LOCK(rt->setSlotLock);
+ saveDepth = JS_SuspendRequest(cx);
+ JS_ACQUIRE_LOCK(rt->setSlotLock);
+ if (rt->setSlotBusy)
+ JS_WAIT_CONDVAR(rt->setSlotDone, JS_NO_TIMEOUT);
+ JS_RELEASE_LOCK(rt->setSlotLock);
+ JS_ResumeRequest(cx, saveDepth);
+ JS_ACQUIRE_LOCK(rt->setSlotLock);
+ }
+ rt->setSlotBusy = JS_TRUE;
+ JS_RELEASE_LOCK(rt->setSlotLock);
+
+#define SET_SLOT_DONE(rt) \
+ JS_BEGIN_MACRO \
+ JS_ACQUIRE_LOCK((rt)->setSlotLock); \
+ (rt)->setSlotBusy = JS_FALSE; \
+ JS_NOTIFY_ALL_CONDVAR((rt)->setSlotDone); \
+ JS_RELEASE_LOCK((rt)->setSlotLock); \
+ JS_END_MACRO
+
+#else
+
+#define SET_SLOT_DONE(rt) /* nothing */
+
+#endif
+
+ obj2 = pobj;
+ while (obj2) {
+ if (obj2 == obj) {
+ SET_SLOT_DONE(rt);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CYCLIC_VALUE,
+#if JS_HAS_OBJ_PROTO_PROP
+ object_props[slot].name
+#else
+ (slot == JSSLOT_PROTO) ? js_proto_str
+ : js_parent_str
+#endif
+ );
+ return JS_FALSE;
+ }
+ obj2 = JSVAL_TO_OBJECT(OBJ_GET_SLOT(cx, obj2, slot));
+ }
+
+ if (slot == JSSLOT_PROTO && OBJ_IS_NATIVE(obj)) {
+ /* Check to see whether obj shares its prototype's scope. */
+ JS_LOCK_OBJ(cx, obj);
+ scope = OBJ_SCOPE(obj);
+ oldproto = JSVAL_TO_OBJECT(LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PROTO));
+ if (oldproto && OBJ_SCOPE(oldproto) == scope) {
+ /* Either obj needs a new empty scope, or it should share pobj's. */
+ if (!pobj ||
+ !OBJ_IS_NATIVE(pobj) ||
+ OBJ_GET_CLASS(cx, pobj) != LOCKED_OBJ_GET_CLASS(oldproto)) {
+ /*
+ * With no proto and no scope of its own, obj is truly empty.
+ *
+ * If pobj is not native, obj needs its own empty scope -- it
+ * should not continue to share oldproto's scope once oldproto
+ * is not on obj's prototype chain. That would put properties
+ * from oldproto's scope ahead of properties defined by pobj,
+ * in lookup order.
+ *
+ * If pobj's class differs from oldproto's, we may need a new
+ * scope to handle differences in private and reserved slots,
+ * so we suboptimally but safely make one.
+ */
+ scope = js_GetMutableScope(cx, obj);
+ if (!scope) {
+ JS_UNLOCK_OBJ(cx, obj);
+ SET_SLOT_DONE(rt);
+ return JS_FALSE;
+ }
+ } else if (OBJ_SCOPE(pobj) != scope) {
+#ifdef JS_THREADSAFE
+ /*
+ * We are about to nest scope locks. Help jslock.c:ShareScope
+ * keep scope->u.count balanced for the JS_UNLOCK_SCOPE, while
+ * avoiding deadlock, by recording scope in rt->setSlotScope.
+ */
+ if (scope->ownercx) {
+ JS_ASSERT(scope->ownercx == cx);
+ rt->setSlotScope = scope;
+ }
+#endif
+
+ /* We can't deadlock because we checked for cycles above (2). */
+ JS_LOCK_OBJ(cx, pobj);
+ newscope = (JSScope *) js_HoldObjectMap(cx, pobj->map);
+ obj->map = &newscope->map;
+ js_DropObjectMap(cx, &scope->map, obj);
+ JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope);
+ scope = newscope;
+#ifdef JS_THREADSAFE
+ rt->setSlotScope = NULL;
+#endif
+ }
+ }
+ LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(pobj));
+ JS_UNLOCK_SCOPE(cx, scope);
+ } else {
+ OBJ_SET_SLOT(cx, obj, slot, OBJECT_TO_JSVAL(pobj));
+ }
+
+ SET_SLOT_DONE(rt);
+ return JS_TRUE;
+
+#undef SET_SLOT_DONE
+}
+
+JS_STATIC_DLL_CALLBACK(JSHashNumber)
+js_hash_object(const void *key)
+{
+ return (JSHashNumber)key >> JSVAL_TAGBITS;
+}
+
+static JSHashEntry *
+MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
+{
+ JSSharpObjectMap *map;
+ JSHashTable *table;
+ JSHashNumber hash;
+ JSHashEntry **hep, *he;
+ jsatomid sharpid;
+ JSIdArray *ida;
+ JSBool ok;
+ jsint i, length;
+ jsid id;
+#if JS_HAS_GETTER_SETTER
+ JSObject *obj2;
+ JSProperty *prop;
+ uintN attrs;
+#endif
+ jsval val;
+
+ map = &cx->sharpObjectMap;
+ table = map->table;
+ hash = js_hash_object(obj);
+ hep = JS_HashTableRawLookup(table, hash, obj);
+ he = *hep;
+ if (!he) {
+ sharpid = 0;
+ he = JS_HashTableRawAdd(table, hep, hash, obj, (void *)sharpid);
+ if (!he) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ ida = JS_Enumerate(cx, obj);
+ if (!ida)
+ return NULL;
+ ok = JS_TRUE;
+ for (i = 0, length = ida->length; i < length; i++) {
+ id = ida->vector[i];
+#if JS_HAS_GETTER_SETTER
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
+ if (!ok)
+ break;
+ if (prop) {
+ ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs);
+ if (ok) {
+ if (OBJ_IS_NATIVE(obj2) &&
+ (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
+ val = JSVAL_NULL;
+ if (attrs & JSPROP_GETTER)
+ val = (jsval) ((JSScopeProperty*)prop)->getter;
+ if (attrs & JSPROP_SETTER) {
+ if (val != JSVAL_NULL) {
+ /* Mark the getter, then set val to setter. */
+ ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val),
+ NULL)
+ != NULL);
+ }
+ val = (jsval) ((JSScopeProperty*)prop)->setter;
+ }
+ } else {
+ ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
+ }
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ }
+#else
+ ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
+#endif
+ if (!ok)
+ break;
+ if (!JSVAL_IS_PRIMITIVE(val) &&
+ !MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) {
+ ok = JS_FALSE;
+ break;
+ }
+ }
+ if (!ok || !idap)
+ JS_DestroyIdArray(cx, ida);
+ if (!ok)
+ return NULL;
+ } else {
+ sharpid = (jsatomid) he->value;
+ if (sharpid == 0) {
+ sharpid = ++map->sharpgen << SHARP_ID_SHIFT;
+ he->value = (void *) sharpid;
+ }
+ ida = NULL;
+ }
+ if (idap)
+ *idap = ida;
+ return he;
+}
+
+JSHashEntry *
+js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
+ jschar **sp)
+{
+ JSSharpObjectMap *map;
+ JSHashTable *table;
+ JSIdArray *ida;
+ JSHashNumber hash;
+ JSHashEntry *he, **hep;
+ jsatomid sharpid;
+ char buf[20];
+ size_t len;
+
+ /* Set to null in case we return an early error. */
+ *sp = NULL;
+ map = &cx->sharpObjectMap;
+ table = map->table;
+ if (!table) {
+ table = JS_NewHashTable(8, js_hash_object, JS_CompareValues,
+ JS_CompareValues, NULL, NULL);
+ if (!table) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ map->table = table;
+ }
+
+ ida = NULL;
+ if (map->depth == 0) {
+ he = MarkSharpObjects(cx, obj, &ida);
+ if (!he)
+ goto bad;
+ JS_ASSERT((((jsatomid) he->value) & SHARP_BIT) == 0);
+ if (!idap) {
+ JS_DestroyIdArray(cx, ida);
+ ida = NULL;
+ }
+ } else {
+ hash = js_hash_object(obj);
+ hep = JS_HashTableRawLookup(table, hash, obj);
+ he = *hep;
+
+ /*
+ * It's possible that the value of a property has changed from the
+ * first time the object's properties are traversed (when the property
+ * ids are entered into the hash table) to the second (when they are
+ * converted to strings), i.e., the OBJ_GET_PROPERTY() call is not
+ * idempotent.
+ */
+ if (!he) {
+ he = JS_HashTableRawAdd(table, hep, hash, obj, NULL);
+ if (!he) {
+ JS_ReportOutOfMemory(cx);
+ goto bad;
+ }
+ *sp = NULL;
+ sharpid = 0;
+ goto out;
+ }
+ }
+
+ sharpid = (jsatomid) he->value;
+ if (sharpid == 0) {
+ *sp = NULL;
+ } else {
+ len = JS_snprintf(buf, sizeof buf, "#%u%c",
+ sharpid >> SHARP_ID_SHIFT,
+ (sharpid & SHARP_BIT) ? '#' : '=');
+ *sp = js_InflateString(cx, buf, len);
+ if (!*sp) {
+ if (ida)
+ JS_DestroyIdArray(cx, ida);
+ goto bad;
+ }
+ }
+
+out:
+ JS_ASSERT(he);
+ if ((sharpid & SHARP_BIT) == 0) {
+ if (idap && !ida) {
+ ida = JS_Enumerate(cx, obj);
+ if (!ida) {
+ if (*sp) {
+ JS_free(cx, *sp);
+ *sp = NULL;
+ }
+ goto bad;
+ }
+ }
+ map->depth++;
+ }
+
+ if (idap)
+ *idap = ida;
+ return he;
+
+bad:
+ /* Clean up the sharpObjectMap table on outermost error. */
+ if (map->depth == 0) {
+ map->sharpgen = 0;
+ JS_HashTableDestroy(map->table);
+ map->table = NULL;
+ }
+ return NULL;
+}
+
+void
+js_LeaveSharpObject(JSContext *cx, JSIdArray **idap)
+{
+ JSSharpObjectMap *map;
+ JSIdArray *ida;
+
+ map = &cx->sharpObjectMap;
+ JS_ASSERT(map->depth > 0);
+ if (--map->depth == 0) {
+ map->sharpgen = 0;
+ JS_HashTableDestroy(map->table);
+ map->table = NULL;
+ }
+ if (idap) {
+ ida = *idap;
+ if (ida) {
+ JS_DestroyIdArray(cx, ida);
+ *idap = NULL;
+ }
+ }
+}
+
+#define OBJ_TOSTRING_EXTRA 3 /* for 3 local GC roots */
+
+#if JS_HAS_INITIALIZERS || JS_HAS_TOSOURCE
+JSBool
+js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSBool ok, outermost;
+ JSHashEntry *he;
+ JSIdArray *ida;
+ jschar *chars, *ochars, *vsharp;
+ const jschar *idstrchars, *vchars;
+ size_t nchars, idstrlength, gsoplength, vlength, vsharplength;
+ char *comma;
+ jsint i, j, length, valcnt;
+ jsid id;
+#if JS_HAS_GETTER_SETTER
+ JSObject *obj2;
+ JSProperty *prop;
+ uintN attrs;
+#endif
+ jsval val[2];
+ JSString *gsop[2];
+ JSAtom *atom;
+ JSString *idstr, *valstr, *str;
+ int stackDummy;
+
+ if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
+ return JS_FALSE;
+ }
+
+ /*
+ * obj_toString for 1.2 calls toSource, and doesn't want the extra parens
+ * on the outside.
+ */
+ outermost = (cx->version != JSVERSION_1_2 && cx->sharpObjectMap.depth == 0);
+ he = js_EnterSharpObject(cx, obj, &ida, &chars);
+ if (!he)
+ return JS_FALSE;
+ if (IS_SHARP(he)) {
+ /*
+ * We didn't enter -- obj is already "sharp", meaning we've visited it
+ * already in our depth first search, and therefore chars contains a
+ * string of the form "#n#".
+ */
+ JS_ASSERT(!ida);
+#if JS_HAS_SHARP_VARS
+ nchars = js_strlen(chars);
+#else
+ chars[0] = '{';
+ chars[1] = '}';
+ chars[2] = 0;
+ nchars = 2;
+#endif
+ goto make_string;
+ }
+ JS_ASSERT(ida);
+ ok = JS_TRUE;
+
+ if (!chars) {
+ /* If outermost, allocate 4 + 1 for "({})" and the terminator. */
+ chars = (jschar *) malloc(((outermost ? 4 : 2) + 1) * sizeof(jschar));
+ nchars = 0;
+ if (!chars)
+ goto error;
+ if (outermost)
+ chars[nchars++] = '(';
+ } else {
+ /* js_EnterSharpObject returned a string of the form "#n=" in chars. */
+ MAKE_SHARP(he);
+ nchars = js_strlen(chars);
+ chars = (jschar *)
+ realloc((ochars = chars), (nchars + 2 + 1) * sizeof(jschar));
+ if (!chars) {
+ free(ochars);
+ goto error;
+ }
+ if (outermost) {
+ /*
+ * No need for parentheses around the whole shebang, because #n=
+ * unambiguously begins an object initializer, and never a block
+ * statement.
+ */
+ outermost = JS_FALSE;
+ }
+ }
+
+ chars[nchars++] = '{';
+
+ comma = NULL;
+
+ for (i = 0, length = ida->length; i < length; i++) {
+ /* Get strings for id and value and GC-root them via argv. */
+ id = ida->vector[i];
+
+#if JS_HAS_GETTER_SETTER
+
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
+ if (!ok)
+ goto error;
+ valcnt = 0;
+ if (prop) {
+ ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs);
+ if (!ok) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ goto error;
+ }
+ if (OBJ_IS_NATIVE(obj2) &&
+ (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
+ if (attrs & JSPROP_GETTER) {
+ val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter;
+#ifdef OLD_GETTER_SETTER
+ gsop[valcnt] =
+ ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
+#else
+ gsop[valcnt] =
+ ATOM_TO_STRING(cx->runtime->atomState.getAtom);
+#endif
+ valcnt++;
+ }
+ if (attrs & JSPROP_SETTER) {
+ val[valcnt] = (jsval) ((JSScopeProperty *)prop)->setter;
+#ifdef OLD_GETTER_SETTER
+ gsop[valcnt] =
+ ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
+#else
+ gsop[valcnt] =
+ ATOM_TO_STRING(cx->runtime->atomState.setAtom);
+#endif
+ valcnt++;
+ }
+ } else {
+ valcnt = 1;
+ gsop[0] = NULL;
+ ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ }
+
+#else /* !JS_HAS_GETTER_SETTER */
+
+ valcnt = 1;
+ gsop[0] = NULL;
+ ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);
+
+#endif /* !JS_HAS_GETTER_SETTER */
+
+ if (!ok)
+ goto error;
+
+ /* Convert id to a jsval and then to a string. */
+ atom = JSVAL_IS_INT(id) ? NULL : (JSAtom *)id;
+ id = ID_TO_VALUE(id);
+ idstr = js_ValueToString(cx, id);
+ if (!idstr) {
+ ok = JS_FALSE;
+ goto error;
+ }
+ argv[0] = STRING_TO_JSVAL(idstr);
+
+ /*
+ * If id is a string that's a reserved identifier, or else id is not
+ * an identifier at all, then it needs to be quoted.
+ */
+ if (atom && (ATOM_KEYWORD(atom) || !js_IsIdentifier(idstr))) {
+ idstr = js_QuoteString(cx, idstr, (jschar)'\'');
+ if (!idstr) {
+ ok = JS_FALSE;
+ goto error;
+ }
+ argv[0] = STRING_TO_JSVAL(idstr);
+ }
+ idstrchars = JSSTRING_CHARS(idstr);
+ idstrlength = JSSTRING_LENGTH(idstr);
+
+ for (j = 0; j < valcnt; j++) {
+ /* Convert val[j] to its canonical source form. */
+ valstr = js_ValueToSource(cx, val[j]);
+ if (!valstr) {
+ ok = JS_FALSE;
+ goto error;
+ }
+ argv[1+j] = STRING_TO_JSVAL(valstr);
+ vchars = JSSTRING_CHARS(valstr);
+ vlength = JSSTRING_LENGTH(valstr);
+
+#ifndef OLD_GETTER_SETTER
+ /* Remove 'function ' from beginning of valstr. */
+ if (gsop[j]) {
+ int n = strlen(js_function_str) + 1;
+ vchars += n;
+ vlength -= n;
+ }
+#endif
+
+ /* If val[j] is a non-sharp object, consider sharpening it. */
+ vsharp = NULL;
+ vsharplength = 0;
+#if JS_HAS_SHARP_VARS
+ if (!JSVAL_IS_PRIMITIVE(val[j]) && vchars[0] != '#') {
+ he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val[j]), NULL,
+ &vsharp);
+ if (!he) {
+ ok = JS_FALSE;
+ goto error;
+ }
+ if (IS_SHARP(he)) {
+ vchars = vsharp;
+ vlength = js_strlen(vchars);
+ } else {
+ if (vsharp) {
+ vsharplength = js_strlen(vsharp);
+ MAKE_SHARP(he);
+ }
+ js_LeaveSharpObject(cx, NULL);
+ }
+ }
+#endif
+
+ /* Allocate 1 + 1 at end for closing brace and terminating 0. */
+ chars = (jschar *)
+ realloc((ochars = chars),
+ (nchars + (comma ? 2 : 0) +
+ idstrlength + 1 +
+ (gsop[j] ? 1 + JSSTRING_LENGTH(gsop[j]) : 0) +
+ vsharplength + vlength +
+ (outermost ? 2 : 1) + 1) * sizeof(jschar));
+ if (!chars) {
+ /* Save code space on error: let JS_free ignore null vsharp. */
+ JS_free(cx, vsharp);
+ free(ochars);
+ goto error;
+ }
+
+ if (comma) {
+ chars[nchars++] = comma[0];
+ chars[nchars++] = comma[1];
+ }
+ comma = ", ";
+
+#ifdef OLD_GETTER_SETTER
+ js_strncpy(&chars[nchars], idstrchars, idstrlength);
+ nchars += idstrlength;
+ if (gsop[j]) {
+ chars[nchars++] = ' ';
+ gsoplength = JSSTRING_LENGTH(gsop[j]);
+ js_strncpy(&chars[nchars], JSSTRING_CHARS(gsop[j]), gsoplength);
+ nchars += gsoplength;
+ }
+ chars[nchars++] = ':';
+#else
+ if (gsop[j]) {
+ gsoplength = JSSTRING_LENGTH(gsop[j]);
+ js_strncpy(&chars[nchars], JSSTRING_CHARS(gsop[j]), gsoplength);
+ nchars += gsoplength;
+ chars[nchars++] = ' ';
+ }
+ js_strncpy(&chars[nchars], idstrchars, idstrlength);
+ nchars += idstrlength;
+ if (!gsop[j])
+ chars[nchars++] = ':';
+#endif
+ if (vsharplength) {
+ js_strncpy(&chars[nchars], vsharp, vsharplength);
+ nchars += vsharplength;
+ }
+ js_strncpy(&chars[nchars], vchars, vlength);
+ nchars += vlength;
+
+ if (vsharp)
+ JS_free(cx, vsharp);
+ }
+ }
+
+ chars[nchars++] = '}';
+ if (outermost)
+ chars[nchars++] = ')';
+ chars[nchars] = 0;
+
+ error:
+ js_LeaveSharpObject(cx, &ida);
+
+ if (!ok) {
+ if (chars)
+ free(chars);
+ return ok;
+ }
+
+ if (!chars) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ make_string:
+ str = js_NewString(cx, chars, nchars, 0);
+ if (!str) {
+ free(chars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif /* JS_HAS_INITIALIZERS || JS_HAS_TOSOURCE */
+
+JSBool
+js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jschar *chars;
+ size_t nchars;
+ const char *clazz, *prefix;
+ JSString *str;
+
+#if JS_HAS_INITIALIZERS
+ if (cx->version == JSVERSION_1_2)
+ return js_obj_toSource(cx, obj, argc, argv, rval);
+#endif
+
+ clazz = OBJ_GET_CLASS(cx, obj)->name;
+ nchars = 9 + strlen(clazz); /* 9 for "[object ]" */
+ chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof(jschar));
+ if (!chars)
+ return JS_FALSE;
+
+ prefix = "[object ";
+ nchars = 0;
+ while ((chars[nchars] = (jschar)*prefix) != 0)
+ nchars++, prefix++;
+ while ((chars[nchars] = (jschar)*clazz) != 0)
+ nchars++, clazz++;
+ chars[nchars++] = ']';
+ chars[nchars] = 0;
+
+ str = js_NewString(cx, chars, nchars, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+obj_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+static JSBool
+obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSStackFrame *fp, *caller;
+ JSBool indirectCall;
+ JSObject *scopeobj;
+ JSString *str;
+ const char *file;
+ uintN line;
+ JSPrincipals *principals;
+ JSScript *script;
+ JSBool ok;
+#if JS_HAS_EVAL_THIS_SCOPE
+ JSObject *callerScopeChain = NULL, *callerVarObj = NULL;
+ JSBool setCallerScopeChain = JS_FALSE, setCallerVarObj = JS_FALSE;
+#endif
+
+ fp = cx->fp;
+ caller = JS_GetScriptedCaller(cx, fp);
+ indirectCall = (caller && caller->pc && *caller->pc != JSOP_EVAL);
+
+ if (JSVERSION_IS_ECMA(cx->version) &&
+ indirectCall &&
+ !JS_ReportErrorFlagsAndNumber(cx,
+ JSREPORT_WARNING | JSREPORT_STRICT,
+ js_GetErrorMessage, NULL,
+ JSMSG_BAD_INDIRECT_CALL,
+ js_eval_str)) {
+ return JS_FALSE;
+ }
+
+ if (!JSVAL_IS_STRING(argv[0])) {
+ *rval = argv[0];
+ return JS_TRUE;
+ }
+
+#if JS_HAS_SCRIPT_OBJECT
+ /*
+ * Script.prototype.compile/exec and Object.prototype.eval all take an
+ * optional trailing argument that overrides the scope object.
+ */
+ scopeobj = NULL;
+ if (argc >= 2) {
+ if (!js_ValueToObject(cx, argv[1], &scopeobj))
+ return JS_FALSE;
+ argv[1] = OBJECT_TO_JSVAL(scopeobj);
+ }
+ if (!scopeobj)
+#endif
+ {
+#if JS_HAS_EVAL_THIS_SCOPE
+ /* If obj.eval(str), emulate 'with (obj) eval(str)' in the caller. */
+ if (indirectCall) {
+ callerScopeChain = caller->scopeChain;
+ if (obj != callerScopeChain) {
+ scopeobj = js_NewObject(cx, &js_WithClass, obj,
+ callerScopeChain);
+ if (!scopeobj)
+ return JS_FALSE;
+
+ /* Set fp->scopeChain too, for the compiler. */
+ caller->scopeChain = fp->scopeChain = scopeobj;
+ setCallerScopeChain = JS_TRUE;
+ }
+
+ callerVarObj = caller->varobj;
+ if (obj != callerVarObj) {
+ /* Set fp->varobj too, for the compiler. */
+ caller->varobj = fp->varobj = obj;
+ setCallerVarObj = JS_TRUE;
+ }
+ }
+ /* From here on, control must exit through label out with ok set. */
+#endif
+
+#if JS_BUG_EVAL_THIS_SCOPE
+ /* An old version used the object in which eval was found for scope. */
+ scopeobj = obj;
+#else
+ /* Compile using caller's current scope object. */
+ if (caller)
+ scopeobj = caller->scopeChain;
+#endif
+ }
+
+ str = JSVAL_TO_STRING(argv[0]);
+ if (caller) {
+ file = caller->script->filename;
+ line = js_PCToLineNumber(cx, caller->script, caller->pc);
+ principals = JS_EvalFramePrincipals(cx, fp, caller);
+ } else {
+ file = NULL;
+ line = 0;
+ principals = NULL;
+ }
+
+ /* XXXbe set only for the compiler, which does not currently test it */
+ fp->flags |= JSFRAME_EVAL;
+ script = JS_CompileUCScriptForPrincipals(cx, scopeobj, principals,
+ JSSTRING_CHARS(str),
+ JSSTRING_LENGTH(str),
+ file, line);
+ if (!script) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+#if !JS_BUG_EVAL_THIS_SCOPE
+#if JS_HAS_SCRIPT_OBJECT
+ if (argc < 2)
+#endif
+ {
+ /* Execute using caller's new scope object (might be a Call object). */
+ if (caller)
+ scopeobj = caller->scopeChain;
+ }
+#endif
+ ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
+ JS_DestroyScript(cx, script);
+
+out:
+#if JS_HAS_EVAL_THIS_SCOPE
+ /* Restore OBJ_GET_PARENT(scopeobj) not callerScopeChain in case of Call. */
+ if (setCallerScopeChain)
+ caller->scopeChain = callerScopeChain;
+ if (setCallerVarObj)
+ caller->varobj = callerVarObj;
+#endif
+ return ok;
+}
+
+JS_STATIC_DLL_CALLBACK(const void *)
+resolving_GetKey(JSDHashTable *table, JSDHashEntryHdr *hdr)
+{
+ JSResolvingEntry *entry = (JSResolvingEntry *)hdr;
+
+ return &entry->key;
+}
+
+JS_STATIC_DLL_CALLBACK(JSDHashNumber)
+resolving_HashKey(JSDHashTable *table, const void *ptr)
+{
+ const JSResolvingKey *key = (const JSResolvingKey *)ptr;
+
+ return ((JSDHashNumber)key->obj >> JSVAL_TAGBITS) ^ key->id;
+}
+
+JS_PUBLIC_API(JSBool)
+resolving_MatchEntry(JSDHashTable *table,
+ const JSDHashEntryHdr *hdr,
+ const void *ptr)
+{
+ const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr;
+ const JSResolvingKey *key = (const JSResolvingKey *)ptr;
+
+ return entry->key.obj == key->obj && entry->key.id == key->id;
+}
+
+static const JSDHashTableOps resolving_dhash_ops = {
+ JS_DHashAllocTable,
+ JS_DHashFreeTable,
+ resolving_GetKey,
+ resolving_HashKey,
+ resolving_MatchEntry,
+ JS_DHashMoveEntryStub,
+ JS_DHashClearEntryStub,
+ JS_DHashFinalizeStub,
+ NULL
+};
+
+static JSBool
+StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
+ JSResolvingEntry **entryp)
+{
+ JSDHashTable *table;
+ JSResolvingEntry *entry;
+
+ table = cx->resolvingTable;
+ if (!table) {
+ table = JS_NewDHashTable(&resolving_dhash_ops, NULL,
+ sizeof(JSResolvingEntry),
+ JS_DHASH_MIN_SIZE);
+ if (!table)
+ goto outofmem;
+ cx->resolvingTable = table;
+ }
+
+ entry = (JSResolvingEntry *)
+ JS_DHashTableOperate(table, key, JS_DHASH_ADD);
+ if (!entry)
+ goto outofmem;
+
+ if (entry->flags & flag) {
+ /* An entry for (key, flag) exists already -- dampen recursion. */
+ entry = NULL;
+ } else {
+ /* Fill in key if we were the first to add entry, then set flag. */
+ if (!entry->key.obj)
+ entry->key = *key;
+ entry->flags |= flag;
+ }
+ *entryp = entry;
+ return JS_TRUE;
+
+outofmem:
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+}
+
+static void
+StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
+ JSResolvingEntry *entry, uint32 generation)
+{
+ JSDHashTable *table;
+
+ /*
+ * Clear flag from entry->flags and return early if other flags remain.
+ * We must take care to re-lookup entry if the table has changed since
+ * it was found by StartResolving.
+ */
+ table = cx->resolvingTable;
+ if (table->generation != generation) {
+ entry = (JSResolvingEntry *)
+ JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP);
+ }
+ entry->flags &= ~flag;
+ if (entry->flags)
+ return;
+
+ /*
+ * Do a raw remove only if fewer entries were removed than would cause
+ * alpha to be less than .5 (alpha is at most .75). Otherwise, we just
+ * call JS_DHashTableOperate to re-lookup the key and remove its entry,
+ * compressing or shrinking the table as needed.
+ */
+ if (table->removedCount < JS_DHASH_TABLE_SIZE(table) >> 2)
+ JS_DHashTableRawRemove(table, &entry->hdr);
+ else
+ JS_DHashTableOperate(table, key, JS_DHASH_REMOVE);
+}
+
+#if JS_HAS_OBJ_WATCHPOINT
+
+static JSBool
+obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp,
+ void *closure)
+{
+ JSResolvingKey key;
+ JSResolvingEntry *entry;
+ uint32 generation;
+ JSObject *funobj;
+ jsval argv[3];
+ JSBool ok;
+
+ /* Avoid recursion on (obj, id) already being watched on cx. */
+ key.obj = obj;
+ key.id = id;
+ if (!StartResolving(cx, &key, JSRESFLAG_WATCH, &entry))
+ return JS_FALSE;
+ if (!entry)
+ return JS_TRUE;
+ generation = cx->resolvingTable->generation;
+
+ funobj = (JSObject *) closure;
+ argv[0] = id;
+ argv[1] = old;
+ argv[2] = *nvp;
+ ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(funobj), 3, argv, nvp);
+ StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation);
+ return ok;
+}
+
+static JSBool
+obj_watch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSFunction *fun;
+ jsval userid, value;
+ jsid propid;
+ uintN attrs;
+
+ fun = js_ValueToFunction(cx, &argv[1], 0);
+ if (!fun)
+ return JS_FALSE;
+ argv[1] = OBJECT_TO_JSVAL(fun->object);
+
+ /* Compute the unique int/atom symbol id needed by js_LookupProperty. */
+ userid = argv[0];
+ if (!JS_ValueToId(cx, userid, &propid))
+ return JS_FALSE;
+
+ if (!OBJ_CHECK_ACCESS(cx, obj, propid, JSACC_WATCH, &value, &attrs))
+ return JS_FALSE;
+ if (attrs & JSPROP_READONLY)
+ return JS_TRUE;
+ return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, fun->object);
+}
+
+static JSBool
+obj_unwatch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return JS_ClearWatchPoint(cx, obj, argv[0], NULL, NULL);
+}
+
+#endif /* JS_HAS_OBJ_WATCHPOINT */
+
+#if JS_HAS_NEW_OBJ_METHODS
+/*
+ * Prototype and property query methods, to complement the 'in' and
+ * 'instanceof' operators.
+ */
+
+/* Proposed ECMA 15.2.4.5. */
+static JSBool
+obj_hasOwnProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsid id;
+ JSObject *obj2;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ *rval = JSVAL_FALSE;
+ } else if (obj2 == obj) {
+ *rval = JSVAL_TRUE;
+ } else if (OBJ_IS_NATIVE(obj2)) {
+ sprop = (JSScopeProperty *)prop;
+ *rval = BOOLEAN_TO_JSVAL(SPROP_IS_SHARED_PERMANENT(sprop));
+ } else {
+ *rval = JSVAL_FALSE;
+ }
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ return JS_TRUE;
+}
+
+/* Proposed ECMA 15.2.4.6. */
+static JSBool
+obj_isPrototypeOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSBool b;
+
+ if (!js_IsDelegate(cx, obj, *argv, &b))
+ return JS_FALSE;
+ *rval = BOOLEAN_TO_JSVAL(b);
+ return JS_TRUE;
+}
+
+/* Proposed ECMA 15.2.4.7. */
+static JSBool
+obj_propertyIsEnumerable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsid id;
+ uintN attrs;
+ JSObject *obj2;
+ JSProperty *prop;
+ JSBool ok;
+
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+ return JS_FALSE;
+
+ if (!prop) {
+ *rval = JSVAL_FALSE;
+ return JS_TRUE;
+ }
+
+ /*
+ * XXX ECMA spec error compatible: return false unless hasOwnProperty.
+ * The ECMA spec really should be fixed so propertyIsEnumerable and the
+ * for..in loop agree on whether prototype properties are enumerable,
+ * obviously by fixing this method (not by breaking the for..in loop!).
+ *
+ * We check here for shared permanent prototype properties, which should
+ * be treated as if they are local to obj. They are an implementation
+ * technique used to satisfy ECMA requirements; users should not be able
+ * to distinguish a shared permanent proto-property from a local one.
+ */
+ if (obj2 != obj &&
+ !(OBJ_IS_NATIVE(obj2) &&
+ SPROP_IS_SHARED_PERMANENT((JSScopeProperty *)prop))) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ *rval = JSVAL_FALSE;
+ return JS_TRUE;
+ }
+
+ ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs);
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ if (ok)
+ *rval = BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0);
+ return ok;
+}
+#endif /* JS_HAS_NEW_OBJ_METHODS */
+
+#if JS_HAS_GETTER_SETTER
+static JSBool
+obj_defineGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval fval, junk;
+ jsid id;
+ JSBool found;
+ uintN attrs;
+
+ fval = argv[1];
+ if (JS_TypeOfValue(cx, fval) != JSTYPE_FUNCTION) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_GETTER_OR_SETTER,
+ js_getter_str);
+ return JS_FALSE;
+ }
+
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+ if (!js_CheckRedeclaration(cx, obj, id, JSPROP_GETTER, &found))
+ return JS_FALSE;
+ /*
+ * Getters and setters are just like watchpoints from an access
+ * control point of view.
+ */
+ if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &junk, &attrs))
+ return JS_FALSE;
+ return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,
+ (JSPropertyOp) JSVAL_TO_OBJECT(fval), NULL,
+ JSPROP_GETTER | JSPROP_SHARED, NULL);
+}
+
+static JSBool
+obj_defineSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval fval, junk;
+ jsid id;
+ JSBool found;
+ uintN attrs;
+
+ fval = argv[1];
+ if (JS_TypeOfValue(cx, fval) != JSTYPE_FUNCTION) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_GETTER_OR_SETTER,
+ js_setter_str);
+ return JS_FALSE;
+ }
+
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+ if (!js_CheckRedeclaration(cx, obj, id, JSPROP_SETTER, &found))
+ return JS_FALSE;
+ /*
+ * Getters and setters are just like watchpoints from an access
+ * control point of view.
+ */
+ if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &junk, &attrs))
+ return JS_FALSE;
+ return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,
+ NULL, (JSPropertyOp) JSVAL_TO_OBJECT(fval),
+ JSPROP_SETTER | JSPROP_SHARED, NULL);
+}
+
+static JSBool
+obj_lookupGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsid id;
+ JSObject *pobj;
+ JSScopeProperty *sprop;
+
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, (JSProperty **) &sprop))
+ return JS_FALSE;
+ if (sprop) {
+ if (sprop->attrs & JSPROP_GETTER)
+ *rval = OBJECT_TO_JSVAL(sprop->getter);
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+obj_lookupSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsid id;
+ JSObject *pobj;
+ JSScopeProperty *sprop;
+
+ if (!JS_ValueToId(cx, argv[0], &id))
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, (JSProperty **) &sprop))
+ return JS_FALSE;
+ if (sprop) {
+ if (sprop->attrs & JSPROP_SETTER)
+ *rval = OBJECT_TO_JSVAL(sprop->setter);
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ }
+ return JS_TRUE;
+}
+#endif /* JS_HAS_GETTER_SETTER */
+
+#if JS_HAS_OBJ_WATCHPOINT
+const char js_watch_str[] = "watch";
+const char js_unwatch_str[] = "unwatch";
+#endif
+#if JS_HAS_NEW_OBJ_METHODS
+const char js_hasOwnProperty_str[] = "hasOwnProperty";
+const char js_isPrototypeOf_str[] = "isPrototypeOf";
+const char js_propertyIsEnumerable_str[] = "propertyIsEnumerable";
+#endif
+#if JS_HAS_GETTER_SETTER
+const char js_defineGetter_str[] = "__defineGetter__";
+const char js_defineSetter_str[] = "__defineSetter__";
+const char js_lookupGetter_str[] = "__lookupGetter__";
+const char js_lookupSetter_str[] = "__lookupSetter__";
+#endif
+
+static JSFunctionSpec object_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, js_obj_toSource, 0, 0, OBJ_TOSTRING_EXTRA},
+#endif
+ {js_toString_str, js_obj_toString, 0, 0, OBJ_TOSTRING_EXTRA},
+ {js_toLocaleString_str, js_obj_toString, 0, 0, OBJ_TOSTRING_EXTRA},
+ {js_valueOf_str, obj_valueOf, 0,0,0},
+ {js_eval_str, obj_eval, 1,0,0},
+#if JS_HAS_OBJ_WATCHPOINT
+ {js_watch_str, obj_watch, 2,0,0},
+ {js_unwatch_str, obj_unwatch, 1,0,0},
+#endif
+#if JS_HAS_NEW_OBJ_METHODS
+ {js_hasOwnProperty_str, obj_hasOwnProperty, 1,0,0},
+ {js_isPrototypeOf_str, obj_isPrototypeOf, 1,0,0},
+ {js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0,0},
+#endif
+#if JS_HAS_GETTER_SETTER
+ {js_defineGetter_str, obj_defineGetter, 2,0,0},
+ {js_defineSetter_str, obj_defineSetter, 2,0,0},
+ {js_lookupGetter_str, obj_lookupGetter, 1,0,0},
+ {js_lookupSetter_str, obj_lookupSetter, 1,0,0},
+#endif
+ {0,0,0,0,0}
+};
+
+static JSBool
+Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (argc == 0) {
+ /* Trigger logic below to construct a blank object. */
+ obj = NULL;
+ } else {
+ /* If argv[0] is null or undefined, obj comes back null. */
+ if (!js_ValueToObject(cx, argv[0], &obj))
+ return JS_FALSE;
+ }
+ if (!obj) {
+ JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
+ if (cx->fp->flags & JSFRAME_CONSTRUCTING)
+ return JS_TRUE;
+ obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ }
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+/*
+ * ObjectOps and Class for with-statement stack objects.
+ */
+static JSBool
+with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp
+#if defined JS_THREADSAFE && defined DEBUG
+ , const char *file, uintN line
+#endif
+ )
+{
+ JSObject *proto;
+ JSScopeProperty *sprop;
+ JSStackFrame *fp;
+
+ proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_LookupProperty(cx, obj, id, objp, propp);
+ if (!OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp))
+ return JS_FALSE;
+
+ /*
+ * Check whether id names an argument or local variable in an active
+ * function. If so, pretend we didn't find it, so that the real arg or
+ * var property can be found in the function's call object, later on in
+ * the scope chain. But skip unshared arg and var properties -- those
+ * result when a script explicitly sets a function "static" property of
+ * the same name. See jsinterp.c:SetFunctionSlot.
+ *
+ * XXX blame pre-ECMA reflection of function args and vars as properties
+ */
+ if ((sprop = (JSScopeProperty *) *propp) &&
+ (proto = *objp, OBJ_IS_NATIVE(proto)) &&
+ (sprop->getter == js_GetArgument ||
+ sprop->getter == js_GetLocalVariable) &&
+ (sprop->attrs & JSPROP_SHARED)) {
+ JS_ASSERT(OBJ_GET_CLASS(cx, proto) == &js_FunctionClass);
+ for (fp = cx->fp; fp && (!fp->fun || fp->fun->native); fp = fp->down)
+ continue;
+ if (fp && fp->fun == (JSFunction *) JS_GetPrivate(cx, proto)) {
+ OBJ_DROP_PROPERTY(cx, proto, *propp);
+ *objp = NULL;
+ *propp = NULL;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+with_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_GetProperty(cx, obj, id, vp);
+ return OBJ_GET_PROPERTY(cx, proto, id, vp);
+}
+
+static JSBool
+with_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_SetProperty(cx, obj, id, vp);
+ return OBJ_SET_PROPERTY(cx, proto, id, vp);
+}
+
+static JSBool
+with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_GetAttributes(cx, obj, id, prop, attrsp);
+ return OBJ_GET_ATTRIBUTES(cx, proto, id, prop, attrsp);
+}
+
+static JSBool
+with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_SetAttributes(cx, obj, id, prop, attrsp);
+ return OBJ_SET_ATTRIBUTES(cx, proto, id, prop, attrsp);
+}
+
+static JSBool
+with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_DeleteProperty(cx, obj, id, rval);
+ return OBJ_DELETE_PROPERTY(cx, proto, id, rval);
+}
+
+static JSBool
+with_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_DefaultValue(cx, obj, hint, vp);
+ return OBJ_DEFAULT_VALUE(cx, proto, hint, vp);
+}
+
+static JSBool
+with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+ jsval *statep, jsid *idp)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_Enumerate(cx, obj, enum_op, statep, idp);
+ return OBJ_ENUMERATE(cx, proto, enum_op, statep, idp);
+}
+
+static JSBool
+with_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
+ jsval *vp, uintN *attrsp)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return js_CheckAccess(cx, obj, id, mode, vp, attrsp);
+ return OBJ_CHECK_ACCESS(cx, proto, id, mode, vp, attrsp);
+}
+
+static JSObject *
+with_ThisObject(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto = OBJ_GET_PROTO(cx, obj);
+ if (!proto)
+ return obj;
+ return OBJ_THIS_OBJECT(cx, proto);
+}
+
+JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
+ js_NewObjectMap, js_DestroyObjectMap,
+ with_LookupProperty, js_DefineProperty,
+ with_GetProperty, with_SetProperty,
+ with_GetAttributes, with_SetAttributes,
+ with_DeleteProperty, with_DefaultValue,
+ with_Enumerate, with_CheckAccess,
+ with_ThisObject, NATIVE_DROP_PROPERTY,
+ NULL, NULL,
+ NULL, NULL,
+ js_SetProtoOrParent, js_SetProtoOrParent,
+ js_Mark, js_Clear,
+ NULL, NULL
+};
+
+static JSObjectOps *
+with_getObjectOps(JSContext *cx, JSClass *clasp)
+{
+ return &js_WithObjectOps;
+}
+
+JSClass js_WithClass = {
+ "With",
+ 0,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ with_getObjectOps,
+ 0,0,0,0,0,0,0
+};
+
+#if JS_HAS_OBJ_PROTO_PROP
+static JSBool
+With(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSObject *parent, *proto;
+ jsval v;
+
+ if (!JS_ReportErrorFlagsAndNumber(cx,
+ JSREPORT_WARNING | JSREPORT_STRICT,
+ js_GetErrorMessage, NULL,
+ JSMSG_DEPRECATED_USAGE,
+ js_WithClass.name)) {
+ return JS_FALSE;
+ }
+
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ obj = js_NewObject(cx, &js_WithClass, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ }
+
+ parent = cx->fp->scopeChain;
+ if (argc > 0) {
+ if (!js_ValueToObject(cx, argv[0], &proto))
+ return JS_FALSE;
+ v = OBJECT_TO_JSVAL(proto);
+ if (!obj_setSlot(cx, obj, INT_TO_JSVAL(JSSLOT_PROTO), &v))
+ return JS_FALSE;
+ if (argc > 1) {
+ if (!js_ValueToObject(cx, argv[1], &parent))
+ return JS_FALSE;
+ }
+ }
+ v = OBJECT_TO_JSVAL(parent);
+ return obj_setSlot(cx, obj, INT_TO_JSVAL(JSSLOT_PARENT), &v);
+}
+#endif
+
+JSObject *
+js_InitObjectClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+ jsval eval;
+
+#if JS_HAS_SHARP_VARS
+ JS_ASSERT(sizeof(jsatomid) * JS_BITS_PER_BYTE >= ATOM_INDEX_LIMIT_LOG2 + 1);
+#endif
+
+ proto = JS_InitClass(cx, obj, NULL, &js_ObjectClass, Object, 1,
+ object_props, object_methods, NULL, NULL);
+ if (!proto)
+ return NULL;
+
+#if JS_HAS_OBJ_PROTO_PROP
+ if (!JS_InitClass(cx, obj, NULL, &js_WithClass, With, 0,
+ NULL, NULL, NULL, NULL)) {
+ return NULL;
+ }
+#endif
+
+ /* ECMA (15.1.2.1) says 'eval' is also a property of the global object. */
+ if (!OBJ_GET_PROPERTY(cx, proto, (jsid)cx->runtime->atomState.evalAtom,
+ &eval)) {
+ return NULL;
+ }
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)cx->runtime->atomState.evalAtom,
+ eval, NULL, NULL, 0, NULL)) {
+ return NULL;
+ }
+
+ return proto;
+}
+
+void
+js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
+ JSClass *clasp)
+{
+ map->nrefs = nrefs;
+ map->ops = ops;
+ map->nslots = JS_INITIAL_NSLOTS;
+ map->freeslot = JSSLOT_FREE(clasp);
+}
+
+JSObjectMap *
+js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
+ JSClass *clasp, JSObject *obj)
+{
+ return (JSObjectMap *) js_NewScope(cx, nrefs, ops, clasp, obj);
+}
+
+void
+js_DestroyObjectMap(JSContext *cx, JSObjectMap *map)
+{
+ js_DestroyScope(cx, (JSScope *)map);
+}
+
+JSObjectMap *
+js_HoldObjectMap(JSContext *cx, JSObjectMap *map)
+{
+ JS_ASSERT(map->nrefs >= 0);
+ JS_ATOMIC_INCREMENT(&map->nrefs);
+ return map;
+}
+
+JSObjectMap *
+js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj)
+{
+ JS_ASSERT(map->nrefs > 0);
+ JS_ATOMIC_DECREMENT(&map->nrefs);
+ if (map->nrefs == 0) {
+ map->ops->destroyObjectMap(cx, map);
+ return NULL;
+ }
+ if (MAP_IS_NATIVE(map) && ((JSScope *)map)->object == obj)
+ ((JSScope *)map)->object = NULL;
+ return map;
+}
+
+static JSBool
+GetClassPrototype(JSContext *cx, JSObject *scope, const char *name,
+ JSObject **protop);
+
+JSObject *
+js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
+{
+ JSObject *obj, *ctor;
+ JSObjectOps *ops;
+ JSObjectMap *map;
+ jsval cval;
+ uint32 nslots, i;
+ jsval *newslots;
+
+ /* Allocate an object from the GC heap and zero it. */
+ obj = (JSObject *) js_AllocGCThing(cx, GCX_OBJECT);
+ if (!obj)
+ return NULL;
+
+ /* Bootstrap the ur-object, and make it the default prototype object. */
+ if (!proto) {
+ if (!GetClassPrototype(cx, parent, clasp->name, &proto))
+ goto bad;
+ if (!proto && !GetClassPrototype(cx, parent, js_Object_str, &proto))
+ goto bad;
+ }
+
+ /* Always call the class's getObjectOps hook if it has one. */
+ ops = clasp->getObjectOps
+ ? clasp->getObjectOps(cx, clasp)
+ : &js_ObjectOps;
+
+ /*
+ * Share proto's map only if it has the same JSObjectOps, and only if
+ * proto's class has the same private and reserved slots, as obj's map
+ * and class have.
+ */
+ if (proto &&
+ (map = proto->map)->ops == ops &&
+ ((clasp->flags ^ OBJ_GET_CLASS(cx, proto)->flags) &
+ (JSCLASS_HAS_PRIVATE |
+ (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT)))
+ == 0) {
+ /* Default parent to the parent of the prototype's constructor. */
+ if (!parent) {
+ if (!OBJ_GET_PROPERTY(cx, proto,
+ (jsid)cx->runtime->atomState.constructorAtom,
+ &cval)) {
+ goto bad;
+ }
+ if (JSVAL_IS_OBJECT(cval) && (ctor = JSVAL_TO_OBJECT(cval)) != NULL)
+ parent = OBJ_GET_PARENT(cx, ctor);
+ }
+
+ /* Share the given prototype's map. */
+ obj->map = js_HoldObjectMap(cx, map);
+
+ /* Ensure that obj starts with the minimum slots for clasp. */
+ nslots = JS_INITIAL_NSLOTS;
+ } else {
+ /* Leave parent alone. Allocate a new map for obj. */
+ map = ops->newObjectMap(cx, 1, ops, clasp, obj);
+ if (!map)
+ goto bad;
+ obj->map = map;
+
+ /* Let ops->newObjectMap set nslots so as to reserve slots. */
+ nslots = map->nslots;
+ }
+
+ /* Allocate a slots vector, with a -1'st element telling its length. */
+ newslots = (jsval *) JS_malloc(cx, (nslots + 1) * sizeof(jsval));
+ if (!newslots) {
+ js_DropObjectMap(cx, obj->map, obj);
+ obj->map = NULL;
+ goto bad;
+ }
+ newslots[0] = nslots;
+ newslots++;
+
+ /* Set the proto, parent, and class properties. */
+ newslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
+ newslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
+ newslots[JSSLOT_CLASS] = PRIVATE_TO_JSVAL(clasp);
+
+ /* Clear above JSSLOT_CLASS so the GC doesn't load uninitialized memory. */
+ for (i = JSSLOT_CLASS + 1; i < nslots; i++)
+ newslots[i] = JSVAL_VOID;
+
+ /* Store newslots after initializing all of 'em, just in case. */
+ obj->slots = newslots;
+
+ if (cx->runtime->objectHook)
+ cx->runtime->objectHook(cx, obj, JS_TRUE, cx->runtime->objectHookData);
+
+ return obj;
+
+bad:
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+}
+
+static JSBool
+FindConstructor(JSContext *cx, JSObject *scope, const char *name, jsval *vp)
+{
+ JSAtom *atom;
+ JSObject *obj;
+ JSObject *pobj;
+ JSScopeProperty *sprop;
+
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+
+ if (scope || (cx->fp && (scope = cx->fp->scopeChain) != NULL)) {
+ /* Find the topmost object in the scope chain. */
+ do {
+ obj = scope;
+ scope = OBJ_GET_PARENT(cx, obj);
+ } while (scope);
+ } else {
+ obj = cx->globalObject;
+ if (!obj) {
+ *vp = JSVAL_VOID;
+ return JS_TRUE;
+ }
+ }
+
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, (JSProperty**)&sprop))
+ return JS_FALSE;
+ if (!sprop) {
+ *vp = JSVAL_VOID;
+ return JS_TRUE;
+ }
+
+ JS_ASSERT(OBJ_IS_NATIVE(pobj));
+ JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)));
+ *vp = OBJ_GET_SLOT(cx, pobj, sprop->slot);
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ return JS_TRUE;
+}
+
+JSObject *
+js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent, uintN argc, jsval *argv)
+{
+ jsval cval, rval;
+ JSObject *obj, *ctor;
+
+ if (!FindConstructor(cx, parent, clasp->name, &cval))
+ return NULL;
+ if (JSVAL_IS_PRIMITIVE(cval)) {
+ js_ReportIsNotFunction(cx, &cval, JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK);
+ return NULL;
+ }
+
+ /*
+ * If proto or parent are NULL, set them to Constructor.prototype and/or
+ * Constructor.__parent__, just like JSOP_NEW does.
+ */
+ ctor = JSVAL_TO_OBJECT(cval);
+ if (!parent)
+ parent = OBJ_GET_PARENT(cx, ctor);
+ if (!proto) {
+ if (!OBJ_GET_PROPERTY(cx, ctor,
+ (jsid)cx->runtime->atomState.classPrototypeAtom,
+ &rval)) {
+ return NULL;
+ }
+ if (JSVAL_IS_OBJECT(rval))
+ proto = JSVAL_TO_OBJECT(rval);
+ }
+
+ obj = js_NewObject(cx, clasp, proto, parent);
+ if (!obj)
+ return NULL;
+
+ if (!js_InternalConstruct(cx, obj, cval, argc, argv, &rval))
+ goto bad;
+ return JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : obj;
+bad:
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+}
+
+void
+js_FinalizeObject(JSContext *cx, JSObject *obj)
+{
+ JSObjectMap *map;
+
+ /* Cope with stillborn objects that have no map. */
+ map = obj->map;
+ if (!map)
+ return;
+ JS_ASSERT(obj->slots);
+
+ if (cx->runtime->objectHook)
+ cx->runtime->objectHook(cx, obj, JS_FALSE, cx->runtime->objectHookData);
+
+ /* Remove all watchpoints with weak links to obj. */
+ JS_ClearWatchPointsForObject(cx, obj);
+
+ /*
+ * Finalize obj first, in case it needs map and slots. Optimized to use
+ * LOCKED_OBJ_GET_CLASS instead of OBJ_GET_CLASS, so we avoid "promoting"
+ * obj's scope from lock-free to lock-full (see jslock.c:ClaimScope) when
+ * we're called from the GC. Only the GC should call js_FinalizeObject,
+ * and no other threads run JS (and possibly racing to update obj->slots)
+ * while the GC is running.
+ */
+ LOCKED_OBJ_GET_CLASS(obj)->finalize(cx, obj);
+
+ /* Drop map and free slots. */
+ js_DropObjectMap(cx, map, obj);
+ obj->map = NULL;
+ JS_free(cx, obj->slots - 1);
+ obj->slots = NULL;
+}
+
+/* XXXbe if one adds props, deletes earlier props, adds more, the last added
+ won't recycle the deleted props' slots. */
+JSBool
+js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
+{
+ JSObjectMap *map;
+ uint32 nslots, i;
+ size_t nbytes;
+ jsval *newslots;
+
+ map = obj->map;
+ JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
+ nslots = map->nslots;
+ if (map->freeslot >= nslots) {
+ nslots = map->freeslot;
+ JS_ASSERT(nslots >= JS_INITIAL_NSLOTS);
+ nslots += (nslots + 1) / 2;
+
+ nbytes = (nslots + 1) * sizeof(jsval);
+#if defined _MSC_VER && _MSC_VER <= 800
+ if (nbytes > 60000U) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+#endif
+
+ newslots = (jsval *) JS_realloc(cx, obj->slots - 1, nbytes);
+ if (!newslots)
+ return JS_FALSE;
+ for (i = 1 + newslots[0]; i <= nslots; i++)
+ newslots[i] = JSVAL_VOID;
+ newslots[0] = map->nslots = nslots;
+ obj->slots = newslots + 1;
+ }
+
+#ifdef TOO_MUCH_GC
+ obj->slots[map->freeslot] = JSVAL_VOID;
+#endif
+ *slotp = map->freeslot++;
+ return JS_TRUE;
+}
+
+void
+js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
+{
+ JSObjectMap *map;
+ uint32 nslots;
+ size_t nbytes;
+ jsval *newslots;
+
+ OBJ_CHECK_SLOT(obj, slot);
+ obj->slots[slot] = JSVAL_VOID;
+ map = obj->map;
+ JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
+ if (map->freeslot == slot + 1)
+ map->freeslot = slot;
+ nslots = map->nslots;
+ if (nslots > JS_INITIAL_NSLOTS && map->freeslot < nslots / 2) {
+ nslots = map->freeslot;
+ nslots += nslots / 2;
+ if (nslots < JS_INITIAL_NSLOTS)
+ nslots = JS_INITIAL_NSLOTS;
+ nbytes = (nslots + 1) * sizeof(jsval);
+ newslots = (jsval *) JS_realloc(cx, obj->slots - 1, nbytes);
+ if (!newslots)
+ return;
+ newslots[0] = map->nslots = nslots;
+ obj->slots = newslots + 1;
+ }
+}
+
+#if JS_BUG_EMPTY_INDEX_ZERO
+#define CHECK_FOR_EMPTY_INDEX(id) \
+ JS_BEGIN_MACRO \
+ if (JSSTRING_LENGTH(_str) == 0) \
+ id = JSVAL_ZERO; \
+ JS_END_MACRO
+#else
+#define CHECK_FOR_EMPTY_INDEX(id) /* nothing */
+#endif
+
+/* JSVAL_INT_MAX as a string */
+#define JSVAL_INT_MAX_STRING "1073741823"
+
+#define CHECK_FOR_FUNNY_INDEX(id) \
+ JS_BEGIN_MACRO \
+ if (!JSVAL_IS_INT(id)) { \
+ JSAtom *atom_ = (JSAtom *)id; \
+ JSString *str_ = ATOM_TO_STRING(atom_); \
+ const jschar *cp_ = str_->chars; \
+ JSBool negative_ = (*cp_ == '-'); \
+ if (negative_) cp_++; \
+ if (JS7_ISDEC(*cp_) && \
+ str_->length - negative_ <= sizeof(JSVAL_INT_MAX_STRING)-1) { \
+ id = CheckForFunnyIndex(id, cp_, negative_); \
+ } else { \
+ CHECK_FOR_EMPTY_INDEX(id); \
+ } \
+ } \
+ JS_END_MACRO
+
+static jsid
+CheckForFunnyIndex(jsid id, const jschar *cp, JSBool negative)
+{
+ jsuint index = JS7_UNDEC(*cp++);
+ jsuint oldIndex = 0;
+ jsuint c = 0;
+
+ if (index != 0) {
+ while (JS7_ISDEC(*cp)) {
+ oldIndex = index;
+ c = JS7_UNDEC(*cp);
+ index = 10 * index + c;
+ cp++;
+ }
+ }
+ if (*cp == 0 &&
+ (oldIndex < (JSVAL_INT_MAX / 10) ||
+ (oldIndex == (JSVAL_INT_MAX / 10) &&
+ c <= (JSVAL_INT_MAX % 10)))) {
+ if (negative)
+ index = 0 - index;
+ id = INT_TO_JSVAL((jsint)index);
+ }
+ return id;
+}
+
+JSScopeProperty *
+js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
+ JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
+ uintN attrs, uintN flags, intN shortid)
+{
+ JSScope *scope;
+ JSScopeProperty *sprop;
+
+ JS_LOCK_OBJ(cx, obj);
+ scope = js_GetMutableScope(cx, obj);
+ if (!scope) {
+ sprop = NULL;
+ } else {
+ /*
+ * Handle old bug that took empty string as zero index. Also convert
+ * string indices to integers if appropriate.
+ */
+ CHECK_FOR_FUNNY_INDEX(id);
+ sprop = js_AddScopeProperty(cx, scope, id, getter, setter, slot, attrs,
+ flags, shortid);
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+ return sprop;
+}
+
+JSScopeProperty *
+js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
+ JSScopeProperty *sprop, uintN attrs, uintN mask,
+ JSPropertyOp getter, JSPropertyOp setter)
+{
+ JSScope *scope;
+
+ JS_LOCK_OBJ(cx, obj);
+ scope = js_GetMutableScope(cx, obj);
+ if (!scope) {
+ sprop = NULL;
+ } else {
+ sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop, attrs, mask,
+ getter, setter);
+ if (sprop) {
+ PROPERTY_CACHE_FILL(&cx->runtime->propertyCache, obj, sprop->id,
+ sprop);
+ }
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+ return sprop;
+}
+
+JSBool
+js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ JSProperty **propp)
+{
+ return js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs,
+ 0, 0, propp);
+}
+
+JSBool
+js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ uintN flags, intN shortid, JSProperty **propp)
+{
+ JSClass *clasp;
+ JSScope *scope;
+ JSScopeProperty *sprop;
+
+ /*
+ * Handle old bug that took empty string as zero index. Also convert
+ * string indices to integers if appropriate.
+ */
+ CHECK_FOR_FUNNY_INDEX(id);
+
+#if JS_HAS_GETTER_SETTER
+ /*
+ * If defining a getter or setter, we must check for its counterpart and
+ * update the attributes and property ops. A getter or setter is really
+ * only half of a property.
+ */
+ if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
+ JSObject *pobj;
+
+ /*
+ * If JS_THREADSAFE and id is found, js_LookupProperty returns with
+ * sprop non-null and pobj locked. If pobj == obj, the property is
+ * already in obj and obj has its own (mutable) scope. So if we are
+ * defining a getter whose setter was already defined, or vice versa,
+ * finish the job via js_ChangeScopePropertyAttributes, and refresh
+ * the property cache line for (obj, id) to map sprop.
+ */
+ if (!js_LookupProperty(cx, obj, id, &pobj, (JSProperty **)&sprop))
+ return JS_FALSE;
+ if (sprop &&
+ pobj == obj &&
+ (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
+ sprop = js_ChangeScopePropertyAttrs(cx, OBJ_SCOPE(obj), sprop,
+ attrs, sprop->attrs,
+ (attrs & JSPROP_GETTER)
+ ? getter
+ : sprop->getter,
+ (attrs & JSPROP_SETTER)
+ ? setter
+ : sprop->setter);
+
+ /* NB: obj == pobj, so we can share unlock code at the bottom. */
+ if (!sprop)
+ goto bad;
+ goto out;
+ }
+
+ if (sprop) {
+ /* NB: call OBJ_DROP_PROPERTY, as pobj might not be native. */
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ sprop = NULL;
+ }
+ }
+#endif /* JS_HAS_GETTER_SETTER */
+
+ /* Lock if object locking is required by this implementation. */
+ JS_LOCK_OBJ(cx, obj);
+
+ /* Use the object's class getter and setter by default. */
+ clasp = LOCKED_OBJ_GET_CLASS(obj);
+ if (!getter)
+ getter = clasp->getProperty;
+ if (!setter)
+ setter = clasp->setProperty;
+
+ /* Get obj's own scope if it has one, or create a new one for obj. */
+ scope = js_GetMutableScope(cx, obj);
+ if (!scope)
+ goto bad;
+
+ /* Add the property to scope, or replace an existing one of the same id. */
+ if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
+ attrs |= JSPROP_SHARED;
+ sprop = js_AddScopeProperty(cx, scope, id, getter, setter,
+ SPROP_INVALID_SLOT, attrs, flags, shortid);
+ if (!sprop)
+ goto bad;
+
+ /* XXXbe called with lock held */
+ if (!clasp->addProperty(cx, obj, SPROP_USERID(sprop), &value)) {
+ (void) js_RemoveScopeProperty(cx, scope, id);
+ goto bad;
+ }
+
+ if (SPROP_HAS_VALID_SLOT(sprop, scope))
+ LOCKED_OBJ_SET_SLOT(obj, sprop->slot, value);
+
+#if JS_HAS_GETTER_SETTER
+out:
+#endif
+ PROPERTY_CACHE_FILL(&cx->runtime->propertyCache, obj, id, sprop);
+ if (propp)
+ *propp = (JSProperty *) sprop;
+ else
+ JS_UNLOCK_OBJ(cx, obj);
+ return JS_TRUE;
+
+bad:
+ JS_UNLOCK_OBJ(cx, obj);
+ return JS_FALSE;
+}
+
+#if defined JS_THREADSAFE && defined DEBUG
+JS_FRIEND_API(JSBool)
+_js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp, const char *file, uintN line)
+#else
+JS_FRIEND_API(JSBool)
+js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp)
+#endif
+{
+ JSObject *start, *obj2, *proto;
+ JSScope *scope;
+ JSScopeProperty *sprop;
+ JSClass *clasp;
+ JSResolveOp resolve;
+ JSResolvingKey key;
+ JSResolvingEntry *entry;
+ uint32 generation;
+ JSNewResolveOp newresolve;
+ uintN flags;
+ uint32 format;
+ JSBool ok;
+
+ /*
+ * Handle old bug that took empty string as zero index. Also convert
+ * string indices to integers if appropriate.
+ */
+ CHECK_FOR_FUNNY_INDEX(id);
+
+ /* Search scopes starting with obj and following the prototype link. */
+ start = obj;
+ for (;;) {
+ JS_LOCK_OBJ(cx, obj);
+ SET_OBJ_INFO(obj, file, line);
+ scope = OBJ_SCOPE(obj);
+ if (scope->object == obj) {
+ sprop = SCOPE_GET_PROPERTY(scope, id);
+ } else {
+ /* Shared prototype scope: try resolve before lookup. */
+ sprop = NULL;
+ }
+
+ /* Try obj's class resolve hook if id was not found in obj's scope. */
+ if (!sprop) {
+ clasp = LOCKED_OBJ_GET_CLASS(obj);
+ resolve = clasp->resolve;
+ if (resolve != JS_ResolveStub) {
+ /* Avoid recursion on (obj, id) already being resolved on cx. */
+ key.obj = obj;
+ key.id = id;
+
+ /*
+ * Once we have successfully added an entry for (obj, key) to
+ * cx->resolvingTable, control must go through cleanup: before
+ * returning. But note that JS_DHASH_ADD may find an existing
+ * entry, in which case we bail to suppress runaway recursion.
+ */
+ if (!StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
+ JS_UNLOCK_OBJ(cx, obj);
+ return JS_FALSE;
+ }
+ if (!entry) {
+ /* Already resolving id in obj -- dampen recursion. */
+ JS_UNLOCK_OBJ(cx, obj);
+ goto out;
+ }
+ generation = cx->resolvingTable->generation;
+
+ /* Null *propp here so we can test it at cleanup: safely. */
+ *propp = NULL;
+
+ if (clasp->flags & JSCLASS_NEW_RESOLVE) {
+ newresolve = (JSNewResolveOp)resolve;
+ flags = 0;
+ if (cx->fp && cx->fp->pc) {
+ format = js_CodeSpec[*cx->fp->pc].format;
+ if ((format & JOF_MODEMASK) != JOF_NAME)
+ flags |= JSRESOLVE_QUALIFIED;
+ if ((format & JOF_ASSIGNING) ||
+ (cx->fp->flags & JSFRAME_ASSIGNING)) {
+ flags |= JSRESOLVE_ASSIGNING;
+ }
+ }
+ obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START)
+ ? start
+ : NULL;
+ JS_UNLOCK_OBJ(cx, obj);
+
+ /* Protect id and all atoms from a GC nested in resolve. */
+ JS_KEEP_ATOMS(cx->runtime);
+ ok = newresolve(cx, obj, ID_TO_VALUE(id), flags, &obj2);
+ JS_UNKEEP_ATOMS(cx->runtime);
+ if (!ok)
+ goto cleanup;
+
+ JS_LOCK_OBJ(cx, obj);
+ SET_OBJ_INFO(obj, file, line);
+ if (obj2) {
+ /* Resolved: juggle locks and lookup id again. */
+ if (obj2 != obj) {
+ JS_UNLOCK_OBJ(cx, obj);
+ JS_LOCK_OBJ(cx, obj2);
+ }
+ scope = OBJ_SCOPE(obj2);
+ if (!MAP_IS_NATIVE(&scope->map)) {
+ /* Whoops, newresolve handed back a foreign obj2. */
+ JS_ASSERT(obj2 != obj);
+ JS_UNLOCK_OBJ(cx, obj2);
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp);
+ if (!ok || *propp)
+ goto cleanup;
+ JS_LOCK_OBJ(cx, obj2);
+ } else {
+ /*
+ * Require that obj2 have its own scope now, as we
+ * do for old-style resolve. If it doesn't, then
+ * id was not truly resolved, and we'll find it in
+ * the proto chain, or miss it if obj2's proto is
+ * not on obj's proto chain. That last case is a
+ * "too bad!" case.
+ */
+ if (scope->object == obj2)
+ sprop = SCOPE_GET_PROPERTY(scope, id);
+ }
+ if (obj2 != obj && !sprop) {
+ JS_UNLOCK_OBJ(cx, obj2);
+ JS_LOCK_OBJ(cx, obj);
+ }
+ }
+ } else {
+ /*
+ * Old resolve always requires id re-lookup if obj owns
+ * its scope after resolve returns.
+ */
+ JS_UNLOCK_OBJ(cx, obj);
+ ok = resolve(cx, obj, ID_TO_VALUE(id));
+ if (!ok)
+ goto cleanup;
+ JS_LOCK_OBJ(cx, obj);
+ SET_OBJ_INFO(obj, file, line);
+ scope = OBJ_SCOPE(obj);
+ JS_ASSERT(MAP_IS_NATIVE(&scope->map));
+ if (scope->object == obj)
+ sprop = SCOPE_GET_PROPERTY(scope, id);
+ }
+
+ cleanup:
+ StopResolving(cx, &key, JSRESFLAG_LOOKUP, entry, generation);
+ if (!ok || *propp)
+ return ok;
+ }
+ }
+
+ if (sprop) {
+ JS_ASSERT(OBJ_SCOPE(obj) == scope);
+ *objp = scope->object; /* XXXbe hide in jsscope.[ch] */
+
+ *propp = (JSProperty *) sprop;
+ return JS_TRUE;
+ }
+
+ proto = LOCKED_OBJ_GET_PROTO(obj);
+ JS_UNLOCK_OBJ(cx, obj);
+ if (!proto)
+ break;
+ if (!OBJ_IS_NATIVE(proto))
+ return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp);
+ obj = proto;
+ }
+
+out:
+ *objp = NULL;
+ *propp = NULL;
+ return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
+ JSProperty **propp)
+{
+ JSRuntime *rt;
+ JSObject *obj, *pobj, *lastobj;
+ JSScopeProperty *sprop;
+ JSProperty *prop;
+
+ rt = cx->runtime;
+ obj = cx->fp->scopeChain;
+ do {
+ /* Try the property cache and return immediately on cache hit. */
+ if (OBJ_IS_NATIVE(obj)) {
+ JS_LOCK_OBJ(cx, obj);
+ PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop);
+ if (sprop) {
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
+ *objp = obj;
+ *pobjp = obj;
+ *propp = (JSProperty *) sprop;
+ return JS_TRUE;
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+ }
+
+ /* If cache miss, take the slow path. */
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
+ return JS_FALSE;
+ if (prop) {
+ if (OBJ_IS_NATIVE(pobj)) {
+ sprop = (JSScopeProperty *) prop;
+ PROPERTY_CACHE_FILL(&rt->propertyCache, pobj, id, sprop);
+ }
+ *objp = obj;
+ *pobjp = pobj;
+ *propp = prop;
+ return JS_TRUE;
+ }
+ lastobj = obj;
+ } while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL);
+
+ *objp = lastobj;
+ *pobjp = NULL;
+ *propp = NULL;
+ return JS_TRUE;
+}
+
+JSObject *
+js_FindIdentifierBase(JSContext *cx, jsid id)
+{
+ JSObject *obj, *pobj;
+ JSProperty *prop;
+
+ /*
+ * Look for id's property along the "with" statement chain and the
+ * statically-linked scope chain.
+ */
+ if (!js_FindProperty(cx, id, &obj, &pobj, &prop))
+ return NULL;
+ if (prop) {
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ return obj;
+ }
+
+ /*
+ * Use the top-level scope from the scope chain, which won't end in the
+ * same scope as cx->globalObject for cross-context function calls.
+ */
+ JS_ASSERT(obj);
+
+ /*
+ * Property not found. Give a strict warning if binding an undeclared
+ * top-level variable.
+ */
+ if (JS_HAS_STRICT_OPTION(cx)) {
+ JSString *str = JSVAL_TO_STRING(ID_TO_VALUE(id));
+ if (!JS_ReportErrorFlagsAndNumber(cx,
+ JSREPORT_WARNING | JSREPORT_STRICT,
+ js_GetErrorMessage, NULL,
+ JSMSG_UNDECLARED_VAR,
+ JS_GetStringBytes(str))) {
+ return NULL;
+ }
+ }
+ return obj;
+}
+
+JSBool
+js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ JSObject *obj2;
+ JSScopeProperty *sprop;
+ JSScope *scope;
+ uint32 slot;
+
+ /*
+ * Handle old bug that took empty string as zero index. Also convert
+ * string indices to integers if appropriate.
+ */
+ CHECK_FOR_FUNNY_INDEX(id);
+
+ if (!js_LookupProperty(cx, obj, id, &obj2, (JSProperty **)&sprop))
+ return JS_FALSE;
+ if (!sprop) {
+ jsval default_val;
+
+#if JS_BUG_NULL_INDEX_PROPS
+ /* Indexed properties defaulted to null in old versions. */
+ default_val = (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0)
+ ? JSVAL_NULL
+ : JSVAL_VOID;
+#else
+ default_val = JSVAL_VOID;
+#endif
+ *vp = default_val;
+
+ if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp))
+ return JS_FALSE;
+
+ /*
+ * Give a strict warning if foo.bar is evaluated by a script for an
+ * object foo with no property named 'bar'.
+ */
+ if (JS_HAS_STRICT_OPTION(cx) &&
+ *vp == default_val &&
+ cx->fp && cx->fp->pc &&
+ (*cx->fp->pc == JSOP_GETPROP || *cx->fp->pc == JSOP_GETELEM))
+ {
+ jsbytecode *pc, *endpc;
+ JSString *str;
+
+ /* Kludge to allow (typeof foo == "undefined") tests. */
+ JS_ASSERT(cx->fp->script);
+ pc = cx->fp->pc;
+ pc += js_CodeSpec[*pc].length;
+ endpc = cx->fp->script->code + cx->fp->script->length;
+ while (pc < endpc) {
+ if (*pc == JSOP_TYPEOF)
+ return JS_TRUE;
+ if (*pc != JSOP_GROUP)
+ break;
+ pc++;
+ }
+
+ /* Ok, bad undefined property reference: whine about it. */
+ str = js_DecompileValueGenerator(cx, JS_FALSE, ID_TO_VALUE(id),
+ NULL);
+ if (!str ||
+ !JS_ReportErrorFlagsAndNumber(cx,
+ JSREPORT_WARNING|JSREPORT_STRICT,
+ js_GetErrorMessage, NULL,
+ JSMSG_UNDEFINED_PROP,
+ JS_GetStringBytes(str))) {
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+ }
+
+ if (!OBJ_IS_NATIVE(obj2)) {
+ OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
+ return OBJ_GET_PROPERTY(cx, obj2, id, vp);
+ }
+
+ /* Unlock obj2 before calling getter, relock after to avoid deadlock. */
+ scope = OBJ_SCOPE(obj2);
+ slot = sprop->slot;
+ if (slot != SPROP_INVALID_SLOT) {
+ JS_ASSERT(slot < obj2->map->freeslot);
+ *vp = LOCKED_OBJ_GET_SLOT(obj2, slot);
+
+ /* If sprop has a stub getter, we're done. */
+ if (!sprop->getter)
+ goto out;
+ } else {
+ *vp = JSVAL_VOID;
+ }
+
+ JS_UNLOCK_SCOPE(cx, scope);
+ if (!SPROP_GET(cx, sprop, obj, obj2, vp))
+ return JS_FALSE;
+ JS_LOCK_SCOPE(cx, scope);
+
+ if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
+ LOCKED_OBJ_SET_SLOT(obj2, slot, *vp);
+ PROPERTY_CACHE_FILL(&cx->runtime->propertyCache, obj2, id, sprop);
+ }
+
+out:
+ JS_UNLOCK_SCOPE(cx, scope);
+ return JS_TRUE;
+}
+
+JSBool
+js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ JSObject *pobj;
+ JSScopeProperty *sprop;
+ JSScope *scope;
+ uintN attrs, flags;
+ intN shortid;
+ JSClass *clasp;
+ JSPropertyOp getter, setter;
+ jsval pval;
+ uint32 slot;
+
+ /*
+ * Handle old bug that took empty string as zero index. Also convert
+ * string indices to integers if appropriate.
+ */
+ CHECK_FOR_FUNNY_INDEX(id);
+
+ if (!js_LookupProperty(cx, obj, id, &pobj, (JSProperty **)&sprop))
+ return JS_FALSE;
+
+ if (sprop && !OBJ_IS_NATIVE(pobj)) {
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ sprop = NULL;
+ }
+
+ /*
+ * Now either sprop is null, meaning id was not found in obj or one of its
+ * prototypes; or sprop is non-null, meaning id was found in pobj's scope.
+ * If JS_THREADSAFE and sprop is non-null, then scope is locked, and sprop
+ * is held: we must OBJ_DROP_PROPERTY or JS_UNLOCK_SCOPE before we return
+ * (the two are equivalent for native objects, but we use JS_UNLOCK_SCOPE
+ * because it is cheaper).
+ */
+ attrs = JSPROP_ENUMERATE;
+ flags = 0;
+ shortid = 0;
+ clasp = OBJ_GET_CLASS(cx, obj);
+ getter = clasp->getProperty;
+ setter = clasp->setProperty;
+
+ if (sprop) {
+ /*
+ * Set scope for use below. It was locked by js_LookupProperty, and
+ * we know pobj owns it (i.e., scope->object == pobj). Therefore we
+ * optimize JS_UNLOCK_OBJ(cx, pobj) into JS_UNLOCK_SCOPE(cx, scope).
+ */
+ scope = OBJ_SCOPE(pobj);
+
+ attrs = sprop->attrs;
+ if ((attrs & JSPROP_READONLY) ||
+ (SCOPE_IS_SEALED(scope) && pobj == obj)) {
+ JS_UNLOCK_SCOPE(cx, scope);
+ if ((attrs & JSPROP_READONLY) && JSVERSION_IS_ECMA(cx->version))
+ return JS_TRUE;
+ goto read_only_error;
+ }
+
+ if (pobj != obj) {
+ /*
+ * We found id in a prototype object: prepare to share or shadow.
+ * NB: Thanks to the immutable, garbage-collected property tree
+ * maintained by jsscope.c in cx->runtime, we needn't worry about
+ * sprop going away behind our back after we've unlocked scope.
+ */
+ JS_UNLOCK_SCOPE(cx, scope);
+
+ /* Don't clone a shared prototype property. */
+ if (attrs & JSPROP_SHARED)
+ return SPROP_SET(cx, sprop, obj, pobj, vp);
+
+ /* Restore attrs to the ECMA default for new properties. */
+ attrs = JSPROP_ENUMERATE;
+
+ /*
+ * Preserve the shortid, getter, and setter when shadowing any
+ * property that has a shortid. An old API convention requires
+ * that the property's getter and setter functions receive the
+ * shortid, not id, when they are called on the shadow we are
+ * about to create in obj's scope.
+ */
+ if (sprop->flags & SPROP_HAS_SHORTID) {
+ flags = SPROP_HAS_SHORTID;
+ shortid = sprop->shortid;
+ getter = sprop->getter;
+ setter = sprop->setter;
+ }
+
+ /*
+ * Forget we found the proto-property now that we've copied any
+ * needed member values.
+ */
+ sprop = NULL;
+ }
+#ifdef __GNUC__ /* suppress bogus gcc warnings */
+ } else {
+ scope = NULL;
+#endif
+ }
+
+ if (!sprop) {
+ if (SCOPE_IS_SEALED(OBJ_SCOPE(obj)) && OBJ_SCOPE(obj)->object == obj)
+ goto read_only_error;
+
+ /* Find or make a property descriptor with the right heritage. */
+ JS_LOCK_OBJ(cx, obj);
+ scope = js_GetMutableScope(cx, obj);
+ if (!scope) {
+ JS_UNLOCK_OBJ(cx, obj);
+ return JS_FALSE;
+ }
+ if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
+ attrs |= JSPROP_SHARED;
+ sprop = js_AddScopeProperty(cx, scope, id, getter, setter,
+ SPROP_INVALID_SLOT, attrs, flags, shortid);
+ if (!sprop) {
+ JS_UNLOCK_SCOPE(cx, scope);
+ return JS_FALSE;
+ }
+
+ /* XXXbe called with obj locked */
+ if (!clasp->addProperty(cx, obj, SPROP_USERID(sprop), vp)) {
+ (void) js_RemoveScopeProperty(cx, scope, id);
+ JS_UNLOCK_SCOPE(cx, scope);
+ return JS_FALSE;
+ }
+
+ /* Initialize new property value (passed to setter) to undefined. */
+ if (SPROP_HAS_VALID_SLOT(sprop, scope))
+ LOCKED_OBJ_SET_SLOT(obj, sprop->slot, JSVAL_VOID);
+
+ PROPERTY_CACHE_FILL(&cx->runtime->propertyCache, obj, id, sprop);
+ }
+
+ /* Get the current property value from its slot. */
+ slot = sprop->slot;
+ if (slot != SPROP_INVALID_SLOT) {
+ JS_ASSERT(slot < obj->map->freeslot);
+ pval = LOCKED_OBJ_GET_SLOT(obj, slot);
+
+ /* If sprop has a stub setter, keep scope locked and just store *vp. */
+ if (!sprop->setter)
+ goto set_slot;
+ }
+
+ /* Avoid deadlock by unlocking obj's scope while calling sprop's setter. */
+ JS_UNLOCK_SCOPE(cx, scope);
+
+ /* Let the setter modify vp before copying from it to obj->slots[slot]. */
+ if (!SPROP_SET(cx, sprop, obj, obj, vp))
+ return JS_FALSE;
+
+ /* Relock obj's scope until we are done with sprop. */
+ JS_LOCK_SCOPE(cx, scope);
+
+ /*
+ * Check whether sprop is still around (was not deleted), and whether it
+ * has a slot (it may never have had one, or we may have lost a race with
+ * someone who cleared scope).
+ */
+ if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
+ set_slot:
+ GC_POKE(cx, pval);
+ LOCKED_OBJ_SET_SLOT(obj, slot, *vp);
+ }
+ JS_UNLOCK_SCOPE(cx, scope);
+ return JS_TRUE;
+
+ read_only_error: {
+ JSString *str = js_DecompileValueGenerator(cx,
+ JSDVG_IGNORE_STACK,
+ ID_TO_VALUE(id),
+ NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_READ_ONLY,
+ JS_GetStringBytes(str));
+ }
+ return JS_FALSE;
+ }
+}
+
+JSBool
+js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp)
+{
+ JSBool noprop, ok;
+ JSScopeProperty *sprop;
+
+ noprop = !prop;
+ if (noprop) {
+ if (!js_LookupProperty(cx, obj, id, &obj, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ *attrsp = 0;
+ return JS_TRUE;
+ }
+ if (!OBJ_IS_NATIVE(obj)) {
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, attrsp);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+ }
+ }
+ sprop = (JSScopeProperty *)prop;
+ *attrsp = sprop->attrs;
+ if (noprop)
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return JS_TRUE;
+}
+
+JSBool
+js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp)
+{
+ JSBool noprop, ok;
+ JSScopeProperty *sprop;
+
+ noprop = !prop;
+ if (noprop) {
+ if (!js_LookupProperty(cx, obj, id, &obj, &prop))
+ return JS_FALSE;
+ if (!prop)
+ return JS_TRUE;
+ if (!OBJ_IS_NATIVE(obj)) {
+ ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, attrsp);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+ }
+ }
+ sprop = (JSScopeProperty *)prop;
+ sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,
+ *attrsp &
+ ~(JSPROP_GETTER | JSPROP_SETTER), 0,
+ sprop->getter, sprop->setter);
+ if (noprop)
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return (sprop != NULL);
+}
+
+JSBool
+js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
+{
+#if JS_HAS_PROP_DELETE
+
+ JSObject *proto;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+ JSString *str;
+ JSScope *scope;
+ JSBool ok;
+
+ *rval = JSVERSION_IS_ECMA(cx->version) ? JSVAL_TRUE : JSVAL_VOID;
+
+ /*
+ * Handle old bug that took empty string as zero index. Also convert
+ * string indices to integers if appropriate.
+ */
+ CHECK_FOR_FUNNY_INDEX(id);
+
+ if (!js_LookupProperty(cx, obj, id, &proto, &prop))
+ return JS_FALSE;
+ if (!prop || proto != obj) {
+ /*
+ * If the property was found in a native prototype, check whether it's
+ * shared and permanent. Such a property stands for direct properties
+ * in all delegating objects, matching ECMA semantics without bloating
+ * each delegating object.
+ */
+ if (prop) {
+ if (OBJ_IS_NATIVE(proto)) {
+ sprop = (JSScopeProperty *)prop;
+ if (SPROP_IS_SHARED_PERMANENT(sprop))
+ *rval = JSVAL_FALSE;
+ }
+ OBJ_DROP_PROPERTY(cx, proto, prop);
+ if (*rval == JSVAL_FALSE)
+ return JS_TRUE;
+ }
+
+ /*
+ * If no property, or the property comes unshared or impermanent from
+ * a prototype, call the class's delProperty hook, passing rval as the
+ * result parameter.
+ */
+ return OBJ_GET_CLASS(cx, obj)->delProperty(cx, obj, ID_TO_VALUE(id),
+ rval);
+ }
+
+ sprop = (JSScopeProperty *)prop;
+ if (sprop->attrs & JSPROP_PERMANENT) {
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ if (JSVERSION_IS_ECMA(cx->version)) {
+ *rval = JSVAL_FALSE;
+ return JS_TRUE;
+ }
+ str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
+ ID_TO_VALUE(id), NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_PERMANENT, JS_GetStringBytes(str));
+ }
+ return JS_FALSE;
+ }
+
+ /* XXXbe called with obj locked */
+ if (!LOCKED_OBJ_GET_CLASS(obj)->delProperty(cx, obj, SPROP_USERID(sprop),
+ rval)) {
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return JS_FALSE;
+ }
+
+ scope = OBJ_SCOPE(obj);
+ if (SPROP_HAS_VALID_SLOT(sprop, scope))
+ GC_POKE(cx, LOCKED_OBJ_GET_SLOT(obj, sprop->slot));
+
+ PROPERTY_CACHE_FILL(&cx->runtime->propertyCache, obj, id, NULL);
+ ok = js_RemoveScopeProperty(cx, scope, id);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+
+#else /* !JS_HAS_PROP_DELETE */
+
+ jsval null = JSVAL_NULL;
+
+ *rval = JSVAL_VOID;
+ return js_SetProperty(cx, obj, id, &null);
+
+#endif /* !JS_HAS_PROP_DELETE */
+}
+
+JSBool
+js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
+{
+ jsval v;
+ JSString *str;
+
+ v = OBJECT_TO_JSVAL(obj);
+ switch (hint) {
+ case JSTYPE_STRING:
+ /*
+ * Propagate the exception if js_TryMethod finds an appropriate
+ * method, and calling that method returned failure.
+ */
+ if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL,
+ &v))
+ return JS_FALSE;
+
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, hint, &v))
+ return JS_FALSE;
+
+ /*
+ * JS1.2 never failed (except for malloc failure) to convert an
+ * object to a string. ECMA requires an error if both toString
+ * and valueOf fail to produce a primitive value.
+ */
+ if (!JSVAL_IS_PRIMITIVE(v) && cx->version == JSVERSION_1_2) {
+ char *bytes = JS_smprintf("[object %s]",
+ OBJ_GET_CLASS(cx, obj)->name);
+ if (!bytes)
+ return JS_FALSE;
+ str = JS_NewString(cx, bytes, strlen(bytes));
+ if (!str) {
+ free(bytes);
+ return JS_FALSE;
+ }
+ v = STRING_TO_JSVAL(str);
+ goto out;
+ }
+ }
+ break;
+
+ default:
+ if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, hint, &v))
+ return JS_FALSE;
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ JSType type = JS_TypeOfValue(cx, v);
+ if (type == hint ||
+ (type == JSTYPE_FUNCTION && hint == JSTYPE_OBJECT)) {
+ goto out;
+ }
+ /* Don't convert to string (source object literal) for JS1.2. */
+ if (cx->version == JSVERSION_1_2 && hint == JSTYPE_BOOLEAN)
+ goto out;
+ if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0,
+ NULL, &v))
+ return JS_FALSE;
+ }
+ break;
+ }
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ /* Avoid recursive death through js_DecompileValueGenerator. */
+ if (hint == JSTYPE_STRING) {
+ str = JS_InternString(cx, OBJ_GET_CLASS(cx, obj)->name);
+ if (!str)
+ return JS_FALSE;
+ } else {
+ str = NULL;
+ }
+ *vp = OBJECT_TO_JSVAL(obj);
+ str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, str);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_CONVERT_TO,
+ JS_GetStringBytes(str),
+ (hint == JSTYPE_VOID)
+ ? "primitive type"
+ : js_type_str[hint]);
+ }
+ return JS_FALSE;
+ }
+out:
+ *vp = v;
+ return JS_TRUE;
+}
+
+JSIdArray *
+js_NewIdArray(JSContext *cx, jsint length)
+{
+ JSIdArray *ida;
+
+ ida = (JSIdArray *)
+ JS_malloc(cx, sizeof(JSIdArray) + (length - 1) * sizeof(jsval));
+ if (ida)
+ ida->length = length;
+ return ida;
+}
+
+JSIdArray *
+js_GrowIdArray(JSContext *cx, JSIdArray *ida, jsint length)
+{
+ ida = (JSIdArray *)
+ JS_realloc(cx, ida, sizeof(JSIdArray) + (length - 1) * sizeof(jsval));
+ if (ida)
+ ida->length = length;
+ return ida;
+}
+
+/* Private type used to iterate over all properties of a native JS object */
+typedef struct JSNativeIteratorState {
+ jsint next_index; /* index into jsid array */
+ JSIdArray *ida; /* All property ids in enumeration */
+} JSNativeIteratorState;
+
+/*
+ * This function is used to enumerate the properties of native JSObjects
+ * and those host objects that do not define a JSNewEnumerateOp-style iterator
+ * function.
+ */
+JSBool
+js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+ jsval *statep, jsid *idp)
+{
+ JSObject *proto_obj;
+ JSClass *clasp;
+ JSEnumerateOp enumerate;
+ JSScopeProperty *sprop, *lastProp;
+ jsint i, length;
+ JSScope *scope;
+ JSIdArray *ida;
+ JSNativeIteratorState *state;
+
+ clasp = OBJ_GET_CLASS(cx, obj);
+ enumerate = clasp->enumerate;
+ if (clasp->flags & JSCLASS_NEW_ENUMERATE)
+ return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
+
+ switch (enum_op) {
+
+ case JSENUMERATE_INIT:
+ if (!enumerate(cx, obj))
+ goto init_error;
+ length = 0;
+
+ /*
+ * The set of all property ids is pre-computed when the iterator
+ * is initialized so as to avoid problems with properties being
+ * deleted during the iteration.
+ */
+ JS_LOCK_OBJ(cx, obj);
+ scope = OBJ_SCOPE(obj);
+
+ /*
+ * If this object shares a scope with its prototype, don't enumerate
+ * its properties. Otherwise they will be enumerated a second time
+ * when the prototype object is enumerated.
+ */
+ proto_obj = OBJ_GET_PROTO(cx, obj);
+ if (proto_obj && scope == OBJ_SCOPE(proto_obj)) {
+ ida = js_NewIdArray(cx, 0);
+ if (!ida) {
+ JS_UNLOCK_OBJ(cx, obj);
+ goto init_error;
+ }
+ } else {
+ /* Object has a private scope; Enumerate all props in scope. */
+ for (sprop = lastProp = SCOPE_LAST_PROP(scope); sprop;
+ sprop = sprop->parent) {
+ if ((sprop->attrs & JSPROP_ENUMERATE) &&
+ !(sprop->flags & SPROP_IS_ALIAS) &&
+ (!SCOPE_HAD_MIDDLE_DELETE(scope) ||
+ SCOPE_HAS_PROPERTY(scope, sprop))) {
+ length++;
+ }
+ }
+ ida = js_NewIdArray(cx, length);
+ if (!ida) {
+ JS_UNLOCK_OBJ(cx, obj);
+ goto init_error;
+ }
+ i = length;
+ for (sprop = lastProp; sprop; sprop = sprop->parent) {
+ if ((sprop->attrs & JSPROP_ENUMERATE) &&
+ !(sprop->flags & SPROP_IS_ALIAS) &&
+ (!SCOPE_HAD_MIDDLE_DELETE(scope) ||
+ SCOPE_HAS_PROPERTY(scope, sprop))) {
+ JS_ASSERT(i > 0);
+ ida->vector[--i] = sprop->id;
+ }
+ }
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+
+ state = (JSNativeIteratorState *)
+ JS_malloc(cx, sizeof(JSNativeIteratorState));
+ if (!state) {
+ JS_DestroyIdArray(cx, ida);
+ goto init_error;
+ }
+ state->ida = ida;
+ state->next_index = 0;
+ *statep = PRIVATE_TO_JSVAL(state);
+ if (idp)
+ *idp = INT_TO_JSVAL(length);
+ return JS_TRUE;
+
+ case JSENUMERATE_NEXT:
+ state = (JSNativeIteratorState *) JSVAL_TO_PRIVATE(*statep);
+ ida = state->ida;
+ length = ida->length;
+ if (state->next_index != length) {
+ *idp = ida->vector[state->next_index++];
+ return JS_TRUE;
+ }
+
+ /* Fall through ... */
+
+ case JSENUMERATE_DESTROY:
+ state = (JSNativeIteratorState *) JSVAL_TO_PRIVATE(*statep);
+ JS_DestroyIdArray(cx, state->ida);
+ JS_free(cx, state);
+ *statep = JSVAL_NULL;
+ return JS_TRUE;
+
+ default:
+ JS_ASSERT(0);
+ return JS_FALSE;
+ }
+
+init_error:
+ *statep = JSVAL_NULL;
+ return JS_FALSE;
+}
+
+JSBool
+js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
+ jsval *vp, uintN *attrsp)
+{
+ JSObject *pobj;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+ JSClass *clasp;
+ JSBool ok;
+
+ if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ *vp = JSVAL_VOID;
+ *attrsp = 0;
+ clasp = OBJ_GET_CLASS(cx, obj);
+ return !clasp->checkAccess ||
+ clasp->checkAccess(cx, obj, ID_TO_VALUE(id), mode, vp);
+ }
+ if (!OBJ_IS_NATIVE(pobj)) {
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ return OBJ_CHECK_ACCESS(cx, pobj, id, mode, vp, attrsp);
+ }
+ sprop = (JSScopeProperty *)prop;
+ *vp = (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)))
+ ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
+ : JSVAL_VOID;
+ *attrsp = sprop->attrs;
+ clasp = LOCKED_OBJ_GET_CLASS(obj);
+ if (clasp->checkAccess) {
+ JS_UNLOCK_OBJ(cx, pobj);
+ ok = clasp->checkAccess(cx, obj, ID_TO_VALUE(id), mode, vp);
+ JS_LOCK_OBJ(cx, pobj);
+ } else {
+ ok = JS_TRUE;
+ }
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ return ok;
+}
+
+#ifdef JS_THREADSAFE
+void
+js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop)
+{
+ JS_UNLOCK_OBJ(cx, obj);
+}
+#endif
+
+static void
+ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
+{
+ /*
+ * The decompiler may need to access the args of the function in
+ * progress rather than the one we had hoped to call.
+ * So we switch the cx->fp to the frame below us. We stick the
+ * current frame in the dormantFrameChain to protect it from gc.
+ */
+
+ JSStackFrame *fp = cx->fp;
+ if (fp->down) {
+ JS_ASSERT(!fp->dormantNext);
+ fp->dormantNext = cx->dormantFrameChain;
+ cx->dormantFrameChain = fp;
+ cx->fp = fp->down;
+ }
+
+ js_ReportIsNotFunction(cx, vp, flags);
+
+ if (fp->down) {
+ JS_ASSERT(cx->dormantFrameChain == fp);
+ cx->dormantFrameChain = fp->dormantNext;
+ fp->dormantNext = NULL;
+ cx->fp = fp;
+ }
+}
+
+JSBool
+js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSClass *clasp;
+
+ clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[-2]));
+ if (!clasp->call) {
+ ReportIsNotFunction(cx, &argv[-2], 0);
+ return JS_FALSE;
+ }
+ return clasp->call(cx, obj, argc, argv, rval);
+}
+
+JSBool
+js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSClass *clasp;
+
+ clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[-2]));
+ if (!clasp->construct) {
+ ReportIsNotFunction(cx, &argv[-2], JSV2F_CONSTRUCT);
+ return JS_FALSE;
+ }
+ return clasp->construct(cx, obj, argc, argv, rval);
+}
+
+JSBool
+js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+{
+ JSClass *clasp;
+
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if (clasp->hasInstance)
+ return clasp->hasInstance(cx, obj, v, bp);
+ *bp = JS_FALSE;
+ return JS_TRUE;
+}
+
+JSBool
+js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+{
+ JSObject *obj2;
+
+ *bp = JS_FALSE;
+ if (JSVAL_IS_PRIMITIVE(v))
+ return JS_TRUE;
+ obj2 = JSVAL_TO_OBJECT(v);
+ while ((obj2 = OBJ_GET_PROTO(cx, obj2)) != NULL) {
+ if (obj2 == obj) {
+ *bp = JS_TRUE;
+ break;
+ }
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_GetClassPrototype(JSContext *cx, const char *name, JSObject **protop)
+{
+ return GetClassPrototype(cx, NULL, name, protop);
+}
+
+static JSBool
+GetClassPrototype(JSContext *cx, JSObject *scope, const char *name,
+ JSObject **protop)
+{
+ jsval v;
+ JSObject *ctor;
+
+ if (!FindConstructor(cx, scope, name, &v))
+ return JS_FALSE;
+ if (JSVAL_IS_FUNCTION(cx, v)) {
+ ctor = JSVAL_TO_OBJECT(v);
+ if (!OBJ_GET_PROPERTY(cx, ctor,
+ (jsid)cx->runtime->atomState.classPrototypeAtom,
+ &v)) {
+ return JS_FALSE;
+ }
+ }
+ *protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL;
+ return JS_TRUE;
+}
+
+JSBool
+js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto,
+ uintN attrs)
+{
+ /*
+ * Use the given attributes for the prototype property of the constructor,
+ * as user-defined constructors have a DontEnum | DontDelete prototype (it
+ * may be reset), while native or "system" constructors require DontEnum |
+ * ReadOnly | DontDelete.
+ */
+ if (!OBJ_DEFINE_PROPERTY(cx, ctor,
+ (jsid)cx->runtime->atomState.classPrototypeAtom,
+ OBJECT_TO_JSVAL(proto), NULL, NULL,
+ attrs, NULL)) {
+ return JS_FALSE;
+ }
+
+ /*
+ * ECMA says that Object.prototype.constructor, or f.prototype.constructor
+ * for a user-defined function f, is DontEnum.
+ */
+ return OBJ_DEFINE_PROPERTY(cx, proto,
+ (jsid)cx->runtime->atomState.constructorAtom,
+ OBJECT_TO_JSVAL(ctor), NULL, NULL,
+ 0, NULL);
+}
+
+JSBool
+js_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
+{
+ JSObject *obj;
+
+ if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) {
+ obj = NULL;
+ } else if (JSVAL_IS_OBJECT(v)) {
+ obj = JSVAL_TO_OBJECT(v);
+ if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_OBJECT, &v))
+ return JS_FALSE;
+ if (JSVAL_IS_OBJECT(v))
+ obj = JSVAL_TO_OBJECT(v);
+ } else {
+ if (JSVAL_IS_STRING(v)) {
+ obj = js_StringToObject(cx, JSVAL_TO_STRING(v));
+ } else if (JSVAL_IS_INT(v)) {
+ obj = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(v));
+ } else if (JSVAL_IS_DOUBLE(v)) {
+ obj = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(v));
+ } else {
+ JS_ASSERT(JSVAL_IS_BOOLEAN(v));
+ obj = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(v));
+ }
+ if (!obj)
+ return JS_FALSE;
+ }
+ *objp = obj;
+ return JS_TRUE;
+}
+
+JSObject *
+js_ValueToNonNullObject(JSContext *cx, jsval v)
+{
+ JSObject *obj;
+ JSString *str;
+
+ if (!js_ValueToObject(cx, v, &obj))
+ return NULL;
+ if (!obj) {
+ str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
+ if (str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_NO_PROPERTIES, JS_GetStringBytes(str));
+ }
+ }
+ return obj;
+}
+
+JSBool
+js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, jsval *rval)
+{
+#if JS_HAS_VALUEOF_HINT
+ jsval argv[1];
+
+ argv[0] = ATOM_KEY(cx->runtime->atomState.typeAtoms[type]);
+ return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, 1, argv,
+ rval);
+#else
+ return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, 0, NULL,
+ rval);
+#endif
+}
+
+JSBool
+js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
+ uintN argc, jsval *argv, jsval *rval)
+{
+ JSErrorReporter older;
+ jsval fval;
+ JSBool ok;
+
+ /*
+ * Report failure only if an appropriate method was found, and calling it
+ * returned failure. We propagate failure in this case to make exceptions
+ * behave properly.
+ */
+ older = JS_SetErrorReporter(cx, NULL);
+ if (OBJ_GET_PROPERTY(cx, obj, (jsid)atom, &fval) &&
+ !JSVAL_IS_PRIMITIVE(fval)) {
+ ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
+ } else {
+ ok = JS_TRUE;
+ }
+ JS_SetErrorReporter(cx, older);
+ return ok;
+}
+
+#if JS_HAS_XDR
+
+#include "jsxdrapi.h"
+
+JSBool
+js_XDRObject(JSXDRState *xdr, JSObject **objp)
+{
+ JSContext *cx;
+ JSClass *clasp;
+ const char *className;
+ uint32 classId, classDef;
+ JSBool ok;
+ JSObject *proto;
+
+ cx = xdr->cx;
+ if (xdr->mode == JSXDR_ENCODE) {
+ clasp = OBJ_GET_CLASS(cx, *objp);
+ className = clasp->name;
+ classId = JS_XDRFindClassIdByName(xdr, className);
+ classDef = !classId;
+ if (classDef && !JS_XDRRegisterClass(xdr, clasp, &classId))
+ return JS_FALSE;
+ } else {
+ classDef = 0;
+ className = NULL;
+ clasp = NULL; /* quell GCC overwarning */
+ }
+
+ /* XDR a flag word followed (if true) by the class name. */
+ if (!JS_XDRUint32(xdr, &classDef))
+ return JS_FALSE;
+ if (classDef && !JS_XDRCString(xdr, (char **) &className))
+ return JS_FALSE;
+
+ /* From here on, return through out: to free className if it was set. */
+ ok = JS_XDRUint32(xdr, &classId);
+ if (!ok)
+ goto out;
+
+ if (xdr->mode != JSXDR_ENCODE) {
+ if (classDef) {
+ ok = js_GetClassPrototype(cx, className, &proto);
+ if (!ok)
+ goto out;
+ clasp = OBJ_GET_CLASS(cx, proto);
+ ok = JS_XDRRegisterClass(xdr, clasp, &classId);
+ if (!ok)
+ goto out;
+ } else {
+ clasp = JS_XDRFindClassById(xdr, classId);
+ if (!clasp) {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)classId);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_FIND_CLASS, numBuf);
+ ok = JS_FALSE;
+ goto out;
+ }
+ }
+ }
+
+ if (!clasp->xdrObject) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_XDR_CLASS, clasp->name);
+ ok = JS_FALSE;
+ } else {
+ ok = clasp->xdrObject(xdr, objp);
+ }
+out:
+ if (xdr->mode != JSXDR_ENCODE && className)
+ JS_free(cx, (void *)className);
+ return ok;
+}
+
+#endif /* JS_HAS_XDR */
+
+#ifdef DEBUG_brendan
+
+#include <stdio.h>
+#include <math.h>
+
+uint32 js_entry_count_max;
+uint32 js_entry_count_sum;
+double js_entry_count_sqsum;
+uint32 js_entry_count_hist[11];
+
+static void
+MeterEntryCount(uintN count)
+{
+ if (count) {
+ js_entry_count_sum += count;
+ js_entry_count_sqsum += (double)count * count;
+ if (count > js_entry_count_max)
+ js_entry_count_max = count;
+ }
+ js_entry_count_hist[JS_MIN(count, 10)]++;
+}
+
+void
+js_DumpScopeMeters(JSRuntime *rt)
+{
+ static FILE *logfp;
+ if (!logfp)
+ logfp = fopen("/tmp/scope.stats", "a");
+
+ {
+ double mean = 0., var = 0., sigma = 0.;
+ double nscopes = rt->liveScopes;
+ double nentrys = js_entry_count_sum;
+ if (nscopes > 0 && nentrys >= 0) {
+ mean = nentrys / nscopes;
+ var = nscopes * js_entry_count_sqsum - nentrys * nentrys;
+ if (var < 0.0 || nscopes <= 1)
+ var = 0.0;
+ else
+ var /= nscopes * (nscopes - 1);
+
+ /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
+ sigma = (var != 0.) ? sqrt(var) : 0.;
+ }
+
+ fprintf(logfp,
+ "scopes %g entries %g mean %g sigma %g max %u",
+ nscopes, nentrys, mean, sigma, js_entry_count_max);
+ }
+
+ fprintf(logfp, " histogram %u %u %u %u %u %u %u %u %u %u %u\n",
+ js_entry_count_hist[0], js_entry_count_hist[1],
+ js_entry_count_hist[2], js_entry_count_hist[3],
+ js_entry_count_hist[4], js_entry_count_hist[5],
+ js_entry_count_hist[6], js_entry_count_hist[7],
+ js_entry_count_hist[8], js_entry_count_hist[9],
+ js_entry_count_hist[10]);
+ js_entry_count_sum = js_entry_count_max = 0;
+ js_entry_count_sqsum = 0;
+ memset(js_entry_count_hist, 0, sizeof js_entry_count_hist);
+ fflush(logfp);
+}
+
+#endif /* DEBUG_brendan */
+
+uint32
+js_Mark(JSContext *cx, JSObject *obj, void *arg)
+{
+ JSScope *scope;
+ JSScopeProperty *sprop;
+ JSClass *clasp;
+
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
+ scope = OBJ_SCOPE(obj);
+#ifdef DEBUG_brendan
+ if (scope->object == obj)
+ MeterEntryCount(scope->entryCount);
+#endif
+
+ JS_ASSERT(!SCOPE_LAST_PROP(scope) ||
+ SCOPE_HAS_PROPERTY(scope, SCOPE_LAST_PROP(scope)));
+
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
+ continue;
+ MARK_SCOPE_PROPERTY(sprop);
+ if (!JSVAL_IS_INT(sprop->id))
+ GC_MARK_ATOM(cx, (JSAtom *)sprop->id, arg);
+
+#if JS_HAS_GETTER_SETTER
+ if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
+#ifdef GC_MARK_DEBUG
+ char buf[64];
+ JSAtom *atom = (JSAtom *)sprop->id;
+ const char *id = (atom && ATOM_IS_STRING(atom))
+ ? JS_GetStringBytes(ATOM_TO_STRING(atom))
+ : "unknown";
+#endif
+
+ if (sprop->attrs & JSPROP_GETTER) {
+#ifdef GC_MARK_DEBUG
+ JS_snprintf(buf, sizeof buf, "%s %s",
+ id, js_getter_str);
+#endif
+ GC_MARK(cx,
+ JSVAL_TO_GCTHING((jsval) sprop->getter),
+ buf,
+ arg);
+ }
+ if (sprop->attrs & JSPROP_SETTER) {
+#ifdef GC_MARK_DEBUG
+ JS_snprintf(buf, sizeof buf, "%s %s",
+ id, js_setter_str);
+#endif
+ GC_MARK(cx,
+ JSVAL_TO_GCTHING((jsval) sprop->setter),
+ buf,
+ arg);
+ }
+ }
+#endif /* JS_HAS_GETTER_SETTER */
+ }
+
+ /* No one runs while the GC is running, so we can use LOCKED_... here. */
+ clasp = LOCKED_OBJ_GET_CLASS(obj);
+ if (clasp->mark)
+ (void) clasp->mark(cx, obj, arg);
+
+ if (scope->object != obj) {
+ /*
+ * An unmutated object that shares a prototype's scope. We can't tell
+ * how many slots are allocated and in use at obj->slots by looking at
+ * scope, so we get obj->slots' length from its -1'st element.
+ */
+ return (uint32) obj->slots[-1];
+ }
+ return JS_MIN(obj->map->freeslot, obj->map->nslots);
+}
+
+void
+js_Clear(JSContext *cx, JSObject *obj)
+{
+ JSScope *scope;
+ JSRuntime *rt;
+ JSScopeProperty *sprop;
+ uint32 i, n;
+
+ /*
+ * Clear our scope and the property cache of all obj's properties only if
+ * obj owns the scope (i.e., not if obj is unmutated and therefore sharing
+ * its prototype's scope). NB: we do not clear any reserved slots lying
+ * below JSSLOT_FREE(clasp).
+ */
+ JS_LOCK_OBJ(cx, obj);
+ scope = OBJ_SCOPE(obj);
+ if (scope->object == obj) {
+ /* Clear the property cache before we clear the scope. */
+ rt = cx->runtime;
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (!SCOPE_HAD_MIDDLE_DELETE(scope) ||
+ SCOPE_HAS_PROPERTY(scope, sprop)) {
+ PROPERTY_CACHE_FILL(&rt->propertyCache, obj, sprop->id, NULL);
+ }
+ }
+
+ /* Now that we're done using scope->lastProp/table, clear scope. */
+ js_ClearScope(cx, scope);
+
+ /* Clear slot values and reset freeslot so we're consistent. */
+ i = scope->map.nslots;
+ n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj));
+ while (--i >= n)
+ obj->slots[i] = JSVAL_VOID;
+ scope->map.freeslot = n;
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+}
+
+jsval
+js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot)
+{
+ jsval v;
+
+ JS_LOCK_OBJ(cx, obj);
+ v = (slot < (uint32) obj->slots[-1]) ? obj->slots[slot] : JSVAL_VOID;
+ JS_UNLOCK_OBJ(cx, obj);
+ return v;
+}
+
+void
+js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
+{
+ uint32 nslots, rlimit, i;
+ JSClass *clasp;
+ jsval *newslots;
+
+ JS_LOCK_OBJ(cx, obj);
+ nslots = (uint32) obj->slots[-1];
+ if (slot >= nslots) {
+ clasp = LOCKED_OBJ_GET_CLASS(obj);
+ rlimit = JSSLOT_START(clasp) + JSCLASS_RESERVED_SLOTS(clasp);
+ JS_ASSERT(slot < rlimit);
+ if (rlimit > nslots)
+ nslots = rlimit;
+
+ newslots = (jsval *)
+ JS_realloc(cx, obj->slots - 1, (nslots + 1) * sizeof(jsval));
+ if (!newslots) {
+ JS_UNLOCK_OBJ(cx, obj);
+ return;
+ }
+ for (i = 1 + newslots[0]; i <= rlimit; i++)
+ newslots[i] = JSVAL_VOID;
+ newslots[0] = nslots;
+ if (OBJ_SCOPE(obj)->object == obj)
+ obj->map->nslots = nslots;
+ obj->slots = newslots + 1;
+ }
+
+ obj->slots[slot] = v;
+ JS_UNLOCK_OBJ(cx, obj);
+}
+
+#ifdef DEBUG
+
+/* Routines to print out values during debugging. */
+
+void printChar(jschar *cp) {
+ fprintf(stderr, "jschar* (0x%p) \"", (void *)cp);
+ while (*cp)
+ fputc(*cp++, stderr);
+ fputc('"', stderr);
+ fputc('\n', stderr);
+}
+
+void printString(JSString *str) {
+ size_t i, n;
+ jschar *s;
+ fprintf(stderr, "string (0x%p) \"", (void *)str);
+ s = JSSTRING_CHARS(str);
+ for (i=0, n=JSSTRING_LENGTH(str); i < n; i++)
+ fputc(s[i], stderr);
+ fputc('"', stderr);
+ fputc('\n', stderr);
+}
+
+void printVal(JSContext *cx, jsval val);
+
+void printObj(JSContext *cx, JSObject *jsobj) {
+ jsuint i;
+ jsval val;
+ JSClass *clasp;
+
+ fprintf(stderr, "object 0x%p\n", (void *)jsobj);
+ clasp = OBJ_GET_CLASS(cx, jsobj);
+ fprintf(stderr, "class 0x%p %s\n", (void *)clasp, clasp->name);
+ for (i=0; i < jsobj->map->nslots; i++) {
+ fprintf(stderr, "slot %3d ", i);
+ val = jsobj->slots[i];
+ if (JSVAL_IS_OBJECT(val))
+ fprintf(stderr, "object 0x%p\n", (void *)JSVAL_TO_OBJECT(val));
+ else
+ printVal(cx, val);
+ }
+}
+
+void printVal(JSContext *cx, jsval val) {
+ fprintf(stderr, "val %d (0x%p) = ", (int)val, (void *)val);
+ if (JSVAL_IS_NULL(val)) {
+ fprintf(stderr, "null\n");
+ } else if (JSVAL_IS_VOID(val)) {
+ fprintf(stderr, "undefined\n");
+ } else if (JSVAL_IS_OBJECT(val)) {
+ printObj(cx, JSVAL_TO_OBJECT(val));
+ } else if (JSVAL_IS_INT(val)) {
+ fprintf(stderr, "(int) %d\n", JSVAL_TO_INT(val));
+ } else if (JSVAL_IS_STRING(val)) {
+ printString(JSVAL_TO_STRING(val));
+ } else if (JSVAL_IS_DOUBLE(val)) {
+ fprintf(stderr, "(double) %g\n", *JSVAL_TO_DOUBLE(val));
+ } else {
+ JS_ASSERT(JSVAL_IS_BOOLEAN(val));
+ fprintf(stderr, "(boolean) %s\n",
+ JSVAL_TO_BOOLEAN(val) ? "true" : "false");
+ }
+ fflush(stderr);
+}
+
+void printId(JSContext *cx, jsid id) {
+ fprintf(stderr, "id %d (0x%p) is ", (int)id, (void *)id);
+ printVal(cx, ID_TO_VALUE(id));
+}
+
+void printAtom(JSAtom *atom) {
+ printString(ATOM_TO_STRING(atom));
+}
+
+#endif
diff --git a/src/dom/js/jsobj.h b/src/dom/js/jsobj.h
new file mode 100644
index 000000000..a523194db
--- /dev/null
+++ b/src/dom/js/jsobj.h
@@ -0,0 +1,464 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsobj_h___
+#define jsobj_h___
+/*
+ * JS object definitions.
+ *
+ * A JS object consists of a possibly-shared object descriptor containing
+ * ordered property names, called the map; and a dense vector of property
+ * values, called slots. The map/slot pointer pair is GC'ed, while the map
+ * is reference counted and the slot vector is malloc'ed.
+ */
+#include "jshash.h" /* Added by JSIFY */
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+struct JSObjectMap {
+ jsrefcount nrefs; /* count of all referencing objects */
+ JSObjectOps *ops; /* high level object operation vtable */
+ uint32 nslots; /* length of obj->slots vector */
+ uint32 freeslot; /* index of next free obj->slots element */
+};
+
+/* Shorthand macros for frequently-made calls. */
+#if defined JS_THREADSAFE && defined DEBUG
+#define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp) \
+ (obj)->map->ops->lookupProperty(cx,obj,id,objp,propp,__FILE__,__LINE__)
+#else
+#define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp) \
+ (obj)->map->ops->lookupProperty(cx,obj,id,objp,propp)
+#endif
+#define OBJ_DEFINE_PROPERTY(cx,obj,id,value,getter,setter,attrs,propp) \
+ (obj)->map->ops->defineProperty(cx,obj,id,value,getter,setter,attrs,propp)
+#define OBJ_GET_PROPERTY(cx,obj,id,vp) \
+ (obj)->map->ops->getProperty(cx,obj,id,vp)
+#define OBJ_SET_PROPERTY(cx,obj,id,vp) \
+ (obj)->map->ops->setProperty(cx,obj,id,vp)
+#define OBJ_GET_ATTRIBUTES(cx,obj,id,prop,attrsp) \
+ (obj)->map->ops->getAttributes(cx,obj,id,prop,attrsp)
+#define OBJ_SET_ATTRIBUTES(cx,obj,id,prop,attrsp) \
+ (obj)->map->ops->setAttributes(cx,obj,id,prop,attrsp)
+#define OBJ_DELETE_PROPERTY(cx,obj,id,rval) \
+ (obj)->map->ops->deleteProperty(cx,obj,id,rval)
+#define OBJ_DEFAULT_VALUE(cx,obj,hint,vp) \
+ (obj)->map->ops->defaultValue(cx,obj,hint,vp)
+#define OBJ_ENUMERATE(cx,obj,enum_op,statep,idp) \
+ (obj)->map->ops->enumerate(cx,obj,enum_op,statep,idp)
+#define OBJ_CHECK_ACCESS(cx,obj,id,mode,vp,attrsp) \
+ (obj)->map->ops->checkAccess(cx,obj,id,mode,vp,attrsp)
+
+/* These four are time-optimized to avoid stub calls. */
+#define OBJ_THIS_OBJECT(cx,obj) \
+ ((obj)->map->ops->thisObject \
+ ? (obj)->map->ops->thisObject(cx,obj) \
+ : (obj))
+#define OBJ_DROP_PROPERTY(cx,obj,prop) \
+ ((obj)->map->ops->dropProperty \
+ ? (obj)->map->ops->dropProperty(cx,obj,prop) \
+ : (void)0)
+#define OBJ_GET_REQUIRED_SLOT(cx,obj,slot) \
+ ((obj)->map->ops->getRequiredSlot \
+ ? (obj)->map->ops->getRequiredSlot(cx, obj, slot) \
+ : JSVAL_VOID)
+#define OBJ_SET_REQUIRED_SLOT(cx,obj,slot,v) \
+ ((obj)->map->ops->setRequiredSlot \
+ ? (obj)->map->ops->setRequiredSlot(cx, obj, slot, v) \
+ : (void)0)
+
+/*
+ * In the original JS engine design, obj->slots pointed to a vector of length
+ * JS_INITIAL_NSLOTS words if obj->map was shared with a prototype object,
+ * else of length obj->map->nslots. With the advent of JS_GetReservedSlot,
+ * JS_SetReservedSlot, and JSCLASS_HAS_RESERVED_SLOTS (see jsapi.h), the size
+ * of the minimum length slots vector in the case where map is shared cannot
+ * be constant. This length starts at JS_INITIAL_NSLOTS, but may advance to
+ * include all the reserved slots.
+ *
+ * Therefore slots must be self-describing. Rather than tag its low order bit
+ * (a bit is all we need) to distinguish initial length from reserved length,
+ * we do "the BSTR thing": over-allocate slots by one jsval, and store the
+ * *net* length (counting usable slots, which have non-negative obj->slots[]
+ * indices) in obj->slots[-1]. All code that sets obj->slots must be aware of
+ * this hack -- you have been warned, and jsobj.c has been updated!
+ */
+struct JSObject {
+ JSObjectMap *map;
+ jsval *slots;
+};
+
+#define JSSLOT_PROTO 0
+#define JSSLOT_PARENT 1
+#define JSSLOT_CLASS 2
+#define JSSLOT_PRIVATE 3
+#define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \
+ ? JSSLOT_PRIVATE + 1 \
+ : JSSLOT_CLASS + 1)
+
+#define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \
+ + JSCLASS_RESERVED_SLOTS(clasp))
+
+#define JS_INITIAL_NSLOTS 5
+
+#ifdef DEBUG
+#define MAP_CHECK_SLOT(map,slot) \
+ JS_ASSERT((uint32)slot < JS_MIN((map)->freeslot, (map)->nslots))
+#define OBJ_CHECK_SLOT(obj,slot) \
+ MAP_CHECK_SLOT((obj)->map, slot)
+#else
+#define OBJ_CHECK_SLOT(obj,slot) ((void)0)
+#endif
+
+/* Fast macros for accessing obj->slots while obj is locked (if thread-safe). */
+#define LOCKED_OBJ_GET_SLOT(obj,slot) \
+ (OBJ_CHECK_SLOT(obj, slot), (obj)->slots[slot])
+#define LOCKED_OBJ_SET_SLOT(obj,slot,value) \
+ (OBJ_CHECK_SLOT(obj, slot), (obj)->slots[slot] = (value))
+#define LOCKED_OBJ_GET_PROTO(obj) \
+ JSVAL_TO_OBJECT(LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PROTO))
+#define LOCKED_OBJ_GET_CLASS(obj) \
+ ((JSClass *)JSVAL_TO_PRIVATE(LOCKED_OBJ_GET_SLOT(obj, JSSLOT_CLASS)))
+
+#ifdef JS_THREADSAFE
+
+/* Thread-safe functions and wrapper macros for accessing obj->slots. */
+#define OBJ_GET_SLOT(cx,obj,slot) \
+ (OBJ_CHECK_SLOT(obj, slot), \
+ (OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->ownercx == cx) \
+ ? LOCKED_OBJ_GET_SLOT(obj, slot) \
+ : js_GetSlotThreadSafe(cx, obj, slot))
+
+#define OBJ_SET_SLOT(cx,obj,slot,value) \
+ (OBJ_CHECK_SLOT(obj, slot), \
+ (OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->ownercx == cx) \
+ ? (void) LOCKED_OBJ_SET_SLOT(obj, slot, value) \
+ : js_SetSlotThreadSafe(cx, obj, slot, value))
+
+/*
+ * If thread-safe, define an OBJ_GET_SLOT wrapper that bypasses, for a native
+ * object, the lock-free "fast path" test of (OBJ_SCOPE(obj)->ownercx == cx),
+ * to avoid needlessly switching from lock-free to lock-full scope when doing
+ * GC on a different context from the last one to own the scope. The caller
+ * in this case is probably a JSClass.mark function, e.g., fun_mark, or maybe
+ * a finalizer.
+ *
+ * The GC runs only when all threads except the one on which the GC is active
+ * are suspended at GC-safe points, so there is no hazard in directly accessing
+ * obj->slots[slot] from the GC's thread, once rt->gcRunning has been set. See
+ * jsgc.c for details.
+ */
+#define THREAD_IS_RUNNING_GC(rt, thread) \
+ ((rt)->gcRunning && (rt)->gcThread == (thread))
+
+#define CX_THREAD_IS_RUNNING_GC(cx) \
+ THREAD_IS_RUNNING_GC((cx)->runtime, (cx)->thread)
+
+#define GC_AWARE_GET_SLOT(cx, obj, slot) \
+ ((OBJ_IS_NATIVE(obj) && CX_THREAD_IS_RUNNING_GC(cx)) \
+ ? (obj)->slots[slot] \
+ : OBJ_GET_SLOT(cx, obj, slot))
+
+#else /* !JS_THREADSAFE */
+
+#define OBJ_GET_SLOT(cx,obj,slot) LOCKED_OBJ_GET_SLOT(obj,slot)
+#define OBJ_SET_SLOT(cx,obj,slot,value) LOCKED_OBJ_SET_SLOT(obj,slot,value)
+#define GC_AWARE_GET_SLOT(cx,obj,slot) LOCKED_OBJ_GET_SLOT(obj,slot)
+
+#endif /* !JS_THREADSAFE */
+
+/* Thread-safe proto, parent, and class access macros. */
+#define OBJ_GET_PROTO(cx,obj) \
+ JSVAL_TO_OBJECT(OBJ_GET_SLOT(cx, obj, JSSLOT_PROTO))
+#define OBJ_SET_PROTO(cx,obj,proto) \
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto))
+
+#define OBJ_GET_PARENT(cx,obj) \
+ JSVAL_TO_OBJECT(OBJ_GET_SLOT(cx, obj, JSSLOT_PARENT))
+#define OBJ_SET_PARENT(cx,obj,parent) \
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent))
+
+#define OBJ_GET_CLASS(cx,obj) \
+ ((JSClass *)JSVAL_TO_PRIVATE(OBJ_GET_SLOT(cx, obj, JSSLOT_CLASS)))
+
+/* Test whether a map or object is native. */
+#define MAP_IS_NATIVE(map) \
+ ((map)->ops == &js_ObjectOps || \
+ ((map)->ops && (map)->ops->newObjectMap == js_ObjectOps.newObjectMap))
+
+#define OBJ_IS_NATIVE(obj) MAP_IS_NATIVE((obj)->map)
+
+extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
+extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps;
+extern JSClass js_ObjectClass;
+extern JSClass js_WithClass;
+
+struct JSSharpObjectMap {
+ jsrefcount depth;
+ jsatomid sharpgen;
+ JSHashTable *table;
+};
+
+#define SHARP_BIT ((jsatomid) 1)
+#define BUSY_BIT ((jsatomid) 2)
+#define SHARP_ID_SHIFT 2
+#define IS_SHARP(he) ((jsatomid)(he)->value & SHARP_BIT)
+#define MAKE_SHARP(he) ((he)->value = (void*)((jsatomid)(he)->value|SHARP_BIT))
+#define IS_BUSY(he) ((jsatomid)(he)->value & BUSY_BIT)
+#define MAKE_BUSY(he) ((he)->value = (void*)((jsatomid)(he)->value|BUSY_BIT))
+#define CLEAR_BUSY(he) ((he)->value = (void*)((jsatomid)(he)->value&~BUSY_BIT))
+
+extern JSHashEntry *
+js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
+ jschar **sp);
+
+extern void
+js_LeaveSharpObject(JSContext *cx, JSIdArray **idap);
+
+extern JSBool
+js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+extern JSBool
+js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+extern JSObject *
+js_InitObjectClass(JSContext *cx, JSObject *obj);
+
+/* Select Object.prototype method names shared between jsapi.c and jsobj.c. */
+extern const char js_watch_str[];
+extern const char js_unwatch_str[];
+extern const char js_hasOwnProperty_str[];
+extern const char js_isPrototypeOf_str[];
+extern const char js_propertyIsEnumerable_str[];
+extern const char js_defineGetter_str[];
+extern const char js_defineSetter_str[];
+extern const char js_lookupGetter_str[];
+extern const char js_lookupSetter_str[];
+
+extern void
+js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
+ JSClass *clasp);
+
+extern JSObjectMap *
+js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
+ JSClass *clasp, JSObject *obj);
+
+extern void
+js_DestroyObjectMap(JSContext *cx, JSObjectMap *map);
+
+extern JSObjectMap *
+js_HoldObjectMap(JSContext *cx, JSObjectMap *map);
+
+extern JSObjectMap *
+js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj);
+
+extern JSObject *
+js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);
+
+extern JSObject *
+js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent, uintN argc, jsval *argv);
+
+extern void
+js_FinalizeObject(JSContext *cx, JSObject *obj);
+
+extern JSBool
+js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp);
+
+extern void
+js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot);
+
+/*
+ * Find or create a property named by id in obj's scope, with the given getter
+ * and setter, slot, attributes, and other members.
+ */
+extern JSScopeProperty *
+js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
+ JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
+ uintN attrs, uintN flags, intN shortid);
+
+/*
+ * Change sprop to have the given attrs, getter, and setter in scope, morphing
+ * it into a potentially new JSScopeProperty. Return a pointer to the changed
+ * or identical property.
+ */
+extern JSScopeProperty *
+js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
+ JSScopeProperty *sprop, uintN attrs, uintN mask,
+ JSPropertyOp getter, JSPropertyOp setter);
+
+/*
+ * On error, return false. On success, if propp is non-null, return true with
+ * obj locked and with a held property in *propp; if propp is null, return true
+ * but release obj's lock first. Therefore all callers who pass non-null propp
+ * result parameters must later call OBJ_DROP_PROPERTY(cx, obj, *propp) both to
+ * drop the held property, and to release the lock on obj.
+ */
+extern JSBool
+js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ JSProperty **propp);
+
+extern JSBool
+js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ uintN flags, intN shortid, JSProperty **propp);
+
+/*
+ * Unlike js_DefineProperty, propp must be non-null. On success, and if id was
+ * found, return true with *objp non-null and locked, and with a held property
+ * stored in *propp. If successful but id was not found, return true with both
+ * *objp and *propp null. Therefore all callers who receive a non-null *propp
+ * must later call OBJ_DROP_PROPERTY(cx, *objp, *propp).
+ */
+#if defined JS_THREADSAFE && defined DEBUG
+extern JS_FRIEND_API(JSBool)
+_js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp, const char *file, uintN line);
+
+#define js_LookupProperty(cx,obj,id,objp,propp) \
+ _js_LookupProperty(cx,obj,id,objp,propp,__FILE__,__LINE__)
+#else
+extern JS_FRIEND_API(JSBool)
+js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp);
+#endif
+
+extern JS_FRIEND_API(JSBool)
+js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
+ JSProperty **propp);
+
+extern JSObject *
+js_FindIdentifierBase(JSContext *cx, jsid id);
+
+extern JSObject *
+js_FindVariableScope(JSContext *cx, JSFunction **funp);
+
+extern JSBool
+js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
+
+extern JSBool
+js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
+
+extern JSBool
+js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp);
+
+extern JSBool
+js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp);
+
+extern JSBool
+js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval);
+
+extern JSBool
+js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp);
+
+extern JSIdArray *
+js_NewIdArray(JSContext *cx, jsint length);
+
+extern JSIdArray *
+js_GrowIdArray(JSContext *cx, JSIdArray *ida, jsint length);
+
+extern JSBool
+js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+ jsval *statep, jsid *idp);
+
+extern JSBool
+js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
+ jsval *vp, uintN *attrsp);
+
+extern JSBool
+js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+extern JSBool
+js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+extern JSBool
+js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
+
+extern JSBool
+js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj);
+
+extern JSBool
+js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
+
+extern JSBool
+js_GetClassPrototype(JSContext *cx, const char *name, JSObject **protop);
+
+extern JSBool
+js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto,
+ uintN attrs);
+
+extern JSBool
+js_ValueToObject(JSContext *cx, jsval v, JSObject **objp);
+
+extern JSObject *
+js_ValueToNonNullObject(JSContext *cx, jsval v);
+
+extern JSBool
+js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, jsval *rval);
+
+extern JSBool
+js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
+ uintN argc, jsval *argv, jsval *rval);
+
+extern JSBool
+js_XDRObject(JSXDRState *xdr, JSObject **objp);
+
+extern uint32
+js_Mark(JSContext *cx, JSObject *obj, void *arg);
+
+extern void
+js_Clear(JSContext *cx, JSObject *obj);
+
+extern jsval
+js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot);
+
+extern void
+js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v);
+
+JS_END_EXTERN_C
+
+#endif /* jsobj_h___ */
diff --git a/src/dom/js/jsopcode.c b/src/dom/js/jsopcode.c
new file mode 100644
index 000000000..166f602d5
--- /dev/null
+++ b/src/dom/js/jsopcode.c
@@ -0,0 +1,2660 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS bytecode descriptors, disassemblers, and decompilers.
+ */
+#include "jsstddef.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsdtoa.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdbgapi.h"
+#include "jsemit.h"
+#include "jsfun.h"
+#include "jslock.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+const char js_const_str[] = "const";
+const char js_var_str[] = "var";
+const char js_function_str[] = "function";
+const char js_in_str[] = "in";
+const char js_instanceof_str[] = "instanceof";
+const char js_new_str[] = "new";
+const char js_delete_str[] = "delete";
+const char js_typeof_str[] = "typeof";
+const char js_void_str[] = "void";
+const char js_null_str[] = "null";
+const char js_this_str[] = "this";
+const char js_false_str[] = "false";
+const char js_true_str[] = "true";
+
+const char *js_incop_str[] = {"++", "--"};
+
+/* Pollute the namespace locally for MSVC Win16, but not for WatCom. */
+#ifdef __WINDOWS_386__
+ #ifdef FAR
+ #undef FAR
+ #endif
+#else /* !__WINDOWS_386__ */
+#ifndef FAR
+#define FAR
+#endif
+#endif /* !__WINDOWS_386__ */
+
+const JSCodeSpec FAR js_CodeSpec[] = {
+#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
+ {name,token,length,nuses,ndefs,prec,format},
+#include "jsopcode.tbl"
+#undef OPDEF
+};
+
+uintN js_NumCodeSpecs = sizeof (js_CodeSpec) / sizeof js_CodeSpec[0];
+
+/************************************************************************/
+
+static ptrdiff_t
+GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
+{
+ uint32 type;
+
+ type = (js_CodeSpec[*pc].format & JOF_TYPEMASK);
+ if (JOF_TYPE_IS_EXTENDED_JUMP(type))
+ return GET_JUMPX_OFFSET(pc2);
+ return GET_JUMP_OFFSET(pc2);
+}
+
+#ifdef DEBUG
+
+JS_FRIEND_API(void)
+js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
+{
+ jsbytecode *pc, *end;
+ uintN len;
+
+ pc = script->code;
+ end = pc + script->length;
+ while (pc < end) {
+ if (pc == script->main)
+ fputs("main:\n", fp);
+ len = js_Disassemble1(cx, script, pc,
+ PTRDIFF(pc, script->code, jsbytecode),
+ lines, fp);
+ if (!len)
+ return;
+ pc += len;
+ }
+}
+
+JS_FRIEND_API(uintN)
+js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
+ JSBool lines, FILE *fp)
+{
+ JSOp op;
+ const JSCodeSpec *cs;
+ intN len, off;
+ JSAtom *atom;
+ JSString *str;
+ char *cstr;
+
+ op = (JSOp)*pc;
+ if (op >= JSOP_LIMIT) {
+ char numBuf1[12], numBuf2[12];
+ JS_snprintf(numBuf1, sizeof numBuf1, "%d", op);
+ JS_snprintf(numBuf2, sizeof numBuf2, "%d", JSOP_LIMIT);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2);
+ return 0;
+ }
+ cs = &js_CodeSpec[op];
+ len = (intN)cs->length;
+ fprintf(fp, "%05u:", loc);
+ if (lines)
+ fprintf(fp, "%4u", JS_PCToLineNumber(cx, script, pc));
+ fprintf(fp, " %s", cs->name);
+ switch (cs->format & JOF_TYPEMASK) {
+ case JOF_BYTE:
+ if (op == JSOP_TRAP) {
+ op = JS_GetTrapOpcode(cx, script, pc);
+ if (op == JSOP_LIMIT)
+ return 0;
+ len = (intN)js_CodeSpec[op].length;
+ }
+ break;
+
+ case JOF_JUMP:
+ case JOF_JUMPX:
+ off = GetJumpOffset(pc, pc);
+ fprintf(fp, " %u (%d)", loc + off, off);
+ break;
+
+ case JOF_CONST:
+ atom = GET_ATOM(cx, script, pc);
+ str = js_ValueToSource(cx, ATOM_KEY(atom));
+ if (!str)
+ return 0;
+ cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
+ if (!cstr)
+ return 0;
+ fprintf(fp, " %s", cstr);
+ JS_free(cx, cstr);
+ break;
+
+ case JOF_UINT16:
+ fprintf(fp, " %u", GET_ARGC(pc));
+ break;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case JOF_TABLESWITCH:
+ {
+ jsbytecode *pc2;
+ jsint i, low, high;
+
+ pc2 = pc;
+ off = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ low = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ high = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ fprintf(fp, " defaultOffset %d low %d high %d", off, low, high);
+ for (i = low; i <= high; i++) {
+ off = GetJumpOffset(pc, pc2);
+ fprintf(fp, "\n\t%d: %d", i, off);
+ pc2 += JUMP_OFFSET_LEN;
+ }
+ len = 1 + pc2 - pc;
+ break;
+ }
+
+ case JOF_LOOKUPSWITCH:
+ {
+ jsbytecode *pc2;
+ jsint npairs;
+
+ pc2 = pc;
+ off = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ npairs = (jsint) GET_ATOM_INDEX(pc2);
+ pc2 += ATOM_INDEX_LEN;
+ fprintf(fp, " offset %d npairs %u", off, (uintN) npairs);
+ while (npairs) {
+ atom = GET_ATOM(cx, script, pc2);
+ pc2 += ATOM_INDEX_LEN;
+ off = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+
+ str = js_ValueToSource(cx, ATOM_KEY(atom));
+ if (!str)
+ return 0;
+ cstr = js_DeflateString(cx, JSSTRING_CHARS(str),
+ JSSTRING_LENGTH(str));
+ if (!cstr)
+ return 0;
+ fprintf(fp, "\n\t%s: %d", cstr, off);
+ JS_free(cx, cstr);
+ npairs--;
+ }
+ len = 1 + pc2 - pc;
+ break;
+ }
+#endif /* JS_HAS_SWITCH_STATEMENT */
+
+ case JOF_QARG:
+ fprintf(fp, " %u", GET_ARGNO(pc));
+ break;
+
+ case JOF_QVAR:
+ fprintf(fp, " %u", GET_VARNO(pc));
+ break;
+
+#if JS_HAS_LEXICAL_CLOSURE
+ case JOF_DEFLOCALVAR:
+ fprintf(fp, " %u", GET_VARNO(pc));
+ pc += VARNO_LEN;
+ atom = GET_ATOM(cx, script, pc);
+ str = js_ValueToSource(cx, ATOM_KEY(atom));
+ if (!str)
+ return 0;
+ cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
+ if (!cstr)
+ return 0;
+ fprintf(fp, " %s", cstr);
+ JS_free(cx, cstr);
+ break;
+#endif
+
+ default: {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_UNKNOWN_FORMAT, numBuf);
+ return 0;
+ }
+ }
+ fputs("\n", fp);
+ return len;
+}
+
+#endif /* DEBUG */
+
+/************************************************************************/
+
+/*
+ * Sprintf, but with unlimited and automatically allocated buffering.
+ */
+typedef struct Sprinter {
+ JSContext *context; /* context executing the decompiler */
+ JSArenaPool *pool; /* string allocation pool */
+ char *base; /* base address of buffer in pool */
+ size_t size; /* size of buffer allocated at base */
+ ptrdiff_t offset; /* offset of next free char in buffer */
+} Sprinter;
+
+#define INIT_SPRINTER(cx, sp, ap, off) \
+ ((sp)->context = cx, (sp)->pool = ap, (sp)->base = NULL, (sp)->size = 0, \
+ (sp)->offset = off)
+
+#define OFF2STR(sp,off) ((sp)->base + (off))
+#define STR2OFF(sp,str) ((str) - (sp)->base)
+#define RETRACT(sp,str) ((sp)->offset = STR2OFF(sp, str))
+
+static JSBool
+SprintAlloc(Sprinter *sp, size_t nb)
+{
+ if (!sp->base) {
+ JS_ARENA_ALLOCATE_CAST(sp->base, char *, sp->pool, nb);
+ } else {
+ JS_ARENA_GROW_CAST(sp->base, char *, sp->pool, sp->size, nb);
+ }
+ if (!sp->base) {
+ JS_ReportOutOfMemory(sp->context);
+ return JS_FALSE;
+ }
+ sp->size += nb;
+ return JS_TRUE;
+}
+
+static ptrdiff_t
+SprintPut(Sprinter *sp, const char *s, size_t len)
+{
+ ptrdiff_t nb, offset;
+ char *bp;
+
+ /* Allocate space for s, including the '\0' at the end. */
+ nb = (sp->offset + len + 1) - sp->size;
+ if (nb > 0 && !SprintAlloc(sp, nb))
+ return -1;
+
+ /* Advance offset and copy s into sp's buffer. */
+ offset = sp->offset;
+ sp->offset += len;
+ bp = sp->base + offset;
+ memmove(bp, s, len);
+ bp[len] = 0;
+ return offset;
+}
+
+static ptrdiff_t
+Sprint(Sprinter *sp, const char *format, ...)
+{
+ va_list ap;
+ char *bp;
+ ptrdiff_t offset;
+
+ va_start(ap, format);
+ bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */
+ va_end(ap);
+ if (!bp) {
+ JS_ReportOutOfMemory(sp->context);
+ return -1;
+ }
+ offset = SprintPut(sp, bp, strlen(bp));
+ free(bp);
+ return offset;
+}
+
+const jschar js_EscapeMap[] = {
+ '\b', 'b',
+ '\f', 'f',
+ '\n', 'n',
+ '\r', 'r',
+ '\t', 't',
+ '\v', 'v',
+ '"', '"',
+ '\'', '\'',
+ '\\', '\\',
+ 0
+};
+
+static char *
+QuoteString(Sprinter *sp, JSString *str, jschar quote)
+{
+ ptrdiff_t off, len, nb;
+ const jschar *s, *t, *u, *z;
+ char *bp;
+ jschar c;
+ JSBool ok;
+
+ /* Sample off first for later return value pointer computation. */
+ off = sp->offset;
+ if (quote && Sprint(sp, "%c", (char)quote) < 0)
+ return NULL;
+
+ /* Loop control variables: z points at end of string sentinel. */
+ s = JSSTRING_CHARS(str);
+ z = s + JSSTRING_LENGTH(str);
+ for (t = s; t < z; s = ++t) {
+ /* Move t forward from s past un-quote-worthy characters. */
+ c = *t;
+ while (JS_ISPRINT(c) && c != quote && c != '\\' && !(c >> 8)) {
+ c = *++t;
+ if (t == z)
+ break;
+ }
+ len = PTRDIFF(t, s, jschar);
+
+ /* Allocate space for s, including the '\0' at the end. */
+ nb = (sp->offset + len + 1) - sp->size;
+ if (nb > 0 && !SprintAlloc(sp, nb))
+ return NULL;
+
+ /* Advance sp->offset and copy s into sp's buffer. */
+ bp = sp->base + sp->offset;
+ sp->offset += len;
+ while (--len >= 0)
+ *bp++ = (char) *s++;
+ *bp = '\0';
+
+ if (t == z)
+ break;
+
+ /* Use js_EscapeMap, \u, or \x only if necessary. */
+ if ((u = js_strchr(js_EscapeMap, c)) != NULL)
+ ok = Sprint(sp, "\\%c", (char)u[1]) >= 0;
+ else
+ ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0;
+ if (!ok)
+ return NULL;
+ }
+
+ /* Sprint the closing quote and return the quoted string. */
+ if (quote && Sprint(sp, "%c", (char)quote) < 0)
+ return NULL;
+ return OFF2STR(sp, off);
+}
+
+JSString *
+js_QuoteString(JSContext *cx, JSString *str, jschar quote)
+{
+ void *mark;
+ Sprinter sprinter;
+ char *bytes;
+ JSString *escstr;
+
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
+ bytes = QuoteString(&sprinter, str, quote);
+ escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL;
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return escstr;
+}
+
+/************************************************************************/
+
+struct JSPrinter {
+ Sprinter sprinter; /* base class state */
+ JSArenaPool pool; /* string allocation pool */
+ uintN indent; /* indentation in spaces */
+ JSBool pretty; /* pretty-print: indent, use newlines */
+ JSScript *script; /* script being printed */
+ JSScope *scope; /* script function scope */
+};
+
+JSPrinter *
+js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty)
+{
+ JSPrinter *jp;
+ JSStackFrame *fp;
+ JSObjectMap *map;
+
+ jp = (JSPrinter *) JS_malloc(cx, sizeof(JSPrinter));
+ if (!jp)
+ return NULL;
+ INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
+ JS_InitArenaPool(&jp->pool, name, 256, 1);
+ jp->indent = indent;
+ jp->pretty = pretty;
+ jp->script = NULL;
+ jp->scope = NULL;
+ fp = cx->fp;
+ if (fp && fp->fun && fp->fun->object) {
+ map = fp->fun->object->map;
+ if (MAP_IS_NATIVE(map))
+ jp->scope = (JSScope *)map;
+ }
+ return jp;
+}
+
+void
+js_DestroyPrinter(JSPrinter *jp)
+{
+ JS_FinishArenaPool(&jp->pool);
+ JS_free(jp->sprinter.context, jp);
+}
+
+JSString *
+js_GetPrinterOutput(JSPrinter *jp)
+{
+ JSContext *cx;
+ JSString *str;
+
+ cx = jp->sprinter.context;
+ if (!jp->sprinter.base)
+ return cx->runtime->emptyString;
+ str = JS_NewStringCopyZ(cx, jp->sprinter.base);
+ if (!str)
+ return NULL;
+ JS_FreeArenaPool(&jp->pool);
+ INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
+ return str;
+}
+
+int
+js_printf(JSPrinter *jp, const char *format, ...)
+{
+ va_list ap;
+ char *bp, *fp;
+ int cc;
+
+ if (*format == '\0')
+ return 0;
+
+ va_start(ap, format);
+
+ /* If pretty-printing, expand magic tab into a run of jp->indent spaces. */
+ if (*format == '\t') {
+ if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0)
+ return -1;
+ format++;
+ }
+
+ /* Suppress newlines (must be once per format, at the end) if not pretty. */
+ fp = NULL;
+ if (!jp->pretty && format[cc = strlen(format)-1] == '\n') {
+ fp = JS_strdup(jp->sprinter.context, format);
+ if (!fp)
+ return -1;
+ fp[cc] = '\0';
+ format = fp;
+ }
+
+ /* Allocate temp space, convert format, and put. */
+ bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */
+ if (fp) {
+ JS_free(jp->sprinter.context, fp);
+ format = NULL;
+ }
+ if (!bp) {
+ JS_ReportOutOfMemory(jp->sprinter.context);
+ return -1;
+ }
+
+ cc = strlen(bp);
+ if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0)
+ cc = -1;
+ free(bp);
+
+ va_end(ap);
+ return cc;
+}
+
+JSBool
+js_puts(JSPrinter *jp, const char *s)
+{
+ return SprintPut(&jp->sprinter, s, strlen(s)) >= 0;
+}
+
+/************************************************************************/
+
+typedef struct SprintStack {
+ Sprinter sprinter; /* sprinter for postfix to infix buffering */
+ ptrdiff_t *offsets; /* stack of postfix string offsets */
+ jsbytecode *opcodes; /* parallel stack of JS opcodes */
+ uintN top; /* top of stack index */
+ JSPrinter *printer; /* permanent output goes here */
+} SprintStack;
+
+/* Gap between stacked strings to allow for insertion of parens and commas. */
+#define PAREN_SLOP (2 + 1)
+
+/*
+ * These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETNAME,
+ * JSOP_SETPROP, and JSOP_SETELEM, respectively. See the first assertion in
+ * PushOff.
+ */
+#define JSOP_GETPROP2 254
+#define JSOP_GETELEM2 255
+
+static JSBool
+PushOff(SprintStack *ss, ptrdiff_t off, JSOp op)
+{
+ uintN top;
+
+#if JSOP_LIMIT > JSOP_GETPROP2
+#error JSOP_LIMIT must be <= JSOP_GETPROP2
+#endif
+ if (!SprintAlloc(&ss->sprinter, PAREN_SLOP))
+ return JS_FALSE;
+
+ /* ss->top points to the next free slot; be paranoid about overflow. */
+ top = ss->top;
+ JS_ASSERT(top < ss->printer->script->depth);
+ if (top >= ss->printer->script->depth) {
+ JS_ReportOutOfMemory(ss->sprinter.context);
+ return JS_FALSE;
+ }
+
+ /* The opcodes stack must contain real bytecodes that index js_CodeSpec. */
+ ss->offsets[top] = off;
+ ss->opcodes[top] = (op == JSOP_GETPROP2) ? JSOP_GETPROP
+ : (op == JSOP_GETELEM2) ? JSOP_GETELEM
+ : (jsbytecode) op;
+ ss->top = ++top;
+ ss->sprinter.offset += PAREN_SLOP;
+ return JS_TRUE;
+}
+
+static ptrdiff_t
+PopOff(SprintStack *ss, JSOp op)
+{
+ uintN top;
+ const JSCodeSpec *cs, *topcs;
+ ptrdiff_t off;
+
+ /* ss->top points to the next free slot; be paranoid about underflow. */
+ top = ss->top;
+ JS_ASSERT(top != 0);
+ if (top == 0)
+ return 0;
+
+ ss->top = --top;
+ topcs = &js_CodeSpec[ss->opcodes[top]];
+ cs = &js_CodeSpec[op];
+ if (topcs->prec != 0 && topcs->prec < cs->prec) {
+ ss->offsets[top] -= 2;
+ ss->sprinter.offset = ss->offsets[top];
+ off = Sprint(&ss->sprinter, "(%s)",
+ OFF2STR(&ss->sprinter, ss->sprinter.offset + 2));
+ } else {
+ off = ss->sprinter.offset = ss->offsets[top];
+ }
+ return off;
+}
+
+#if JS_HAS_SWITCH_STATEMENT
+typedef struct TableEntry {
+ jsval key;
+ ptrdiff_t offset;
+} TableEntry;
+
+static int
+CompareOffsets(const void *v1, const void *v2, void *arg)
+{
+ const TableEntry *te1 = (const TableEntry *) v1,
+ *te2 = (const TableEntry *) v2;
+
+ return te1->offset - te2->offset;
+}
+
+static JSBool
+Decompile(SprintStack *ss, jsbytecode *pc, intN nb);
+
+static JSBool
+DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
+ jsbytecode *pc, ptrdiff_t switchLength,
+ ptrdiff_t defaultOffset, JSBool isCondSwitch)
+{
+ JSContext *cx;
+ JSPrinter *jp;
+ char *lval, *rval;
+ uintN i;
+ ptrdiff_t diff, off, off2, caseExprOff;
+ jsval key;
+ JSString *str;
+
+ cx = ss->sprinter.context;
+ jp = ss->printer;
+
+ lval = OFF2STR(&ss->sprinter, PopOff(ss, JSOP_NOP));
+ js_printf(jp, "\tswitch (%s) {\n", lval);
+
+ if (tableLength) {
+ diff = table[0].offset - defaultOffset;
+ if (diff > 0) {
+ jp->indent += 2;
+ js_printf(jp, "\tdefault:\n");
+ jp->indent += 2;
+ if (!Decompile(ss, pc + defaultOffset, diff))
+ return JS_FALSE;
+ jp->indent -= 4;
+ }
+
+ caseExprOff = isCondSwitch
+ ? (ptrdiff_t) js_CodeSpec[JSOP_CONDSWITCH].length
+ : 0;
+
+ for (i = 0; i < tableLength; i++) {
+ off = table[i].offset;
+ if (i + 1 < tableLength)
+ off2 = table[i + 1].offset;
+ else
+ off2 = switchLength;
+
+ key = table[i].key;
+ if (isCondSwitch) {
+ ptrdiff_t nextCaseExprOff;
+
+ /*
+ * key encodes the JSOP_CASE bytecode's offset from switchtop.
+ * The next case expression follows immediately, unless we are
+ * at the last case.
+ */
+ nextCaseExprOff = (ptrdiff_t)JSVAL_TO_INT(key);
+ nextCaseExprOff += js_CodeSpec[pc[nextCaseExprOff]].length;
+ jp->indent += 2;
+ if (!Decompile(ss, pc + caseExprOff,
+ nextCaseExprOff - caseExprOff)) {
+ return JS_FALSE;
+ }
+ caseExprOff = nextCaseExprOff;
+ } else {
+ /*
+ * key comes from an atom, not the decompiler, so we need to
+ * quote it if it's a string literal.
+ */
+ str = js_ValueToString(cx, key);
+ if (!str)
+ return JS_FALSE;
+ jp->indent += 2;
+ if (JSVAL_IS_STRING(key)) {
+ rval = QuoteString(&ss->sprinter, str, (jschar)'"');
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ } else {
+ rval = JS_GetStringBytes(str);
+ }
+ js_printf(jp, "\tcase %s:\n", rval);
+ }
+
+ jp->indent += 2;
+ if (off <= defaultOffset && defaultOffset < off2) {
+ diff = defaultOffset - off;
+ if (diff != 0) {
+ if (!Decompile(ss, pc + off, diff))
+ return JS_FALSE;
+ off = defaultOffset;
+ }
+ jp->indent -= 2;
+ js_printf(jp, "\tdefault:\n");
+ jp->indent += 2;
+ }
+ if (!Decompile(ss, pc + off, off2 - off))
+ return JS_FALSE;
+ jp->indent -= 4;
+ }
+ }
+
+ if (defaultOffset == switchLength) {
+ jp->indent += 2;
+ js_printf(jp, "\tdefault:\n");
+ jp->indent -= 2;
+ }
+ js_printf(jp, "\t}\n");
+ return JS_TRUE;
+}
+#endif
+
+static JSAtom *
+GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot)
+{
+ JSScope *scope;
+ JSScopeProperty *sprop;
+ JSObject *obj, *proto;
+
+ scope = jp->scope;
+ while (scope) {
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (sprop->getter != getter)
+ continue;
+ JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
+ JS_ASSERT(!JSVAL_IS_INT(sprop->id));
+ if ((uintN) sprop->shortid == slot)
+ return (JSAtom *) sprop->id;
+ }
+ obj = scope->object;
+ if (!obj)
+ break;
+ proto = OBJ_GET_PROTO(jp->sprinter.context, obj);
+ if (!proto)
+ break;
+ scope = OBJ_SCOPE(proto);
+ }
+ return NULL;
+}
+
+static const char *
+VarPrefix(jssrcnote *sn)
+{
+ const char *kw;
+ static char buf[8];
+
+ kw = NULL;
+ if (sn) {
+ if (SN_TYPE(sn) == SRC_VAR)
+ kw = js_var_str;
+ else if (SN_TYPE(sn) == SRC_CONST)
+ kw = js_const_str;
+ }
+ if (!kw)
+ return "";
+ JS_snprintf(buf, sizeof buf, "%s ", kw);
+ return buf;
+}
+
+static JSBool
+Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
+{
+ JSContext *cx;
+ JSPrinter *jp, *jp2;
+ jsbytecode *endpc, *done, *forelem_tail, *forelem_done;
+ ptrdiff_t len, todo, oplen, cond, next, tail;
+ JSOp op, lastop, saveop;
+ const JSCodeSpec *cs, *topcs;
+ jssrcnote *sn, *sn2;
+ const char *lval, *rval, *xval, *fmt;
+ jsint i, argc;
+ char **argv;
+ JSAtom *atom;
+ JSObject *obj;
+ JSFunction *fun;
+ JSString *str;
+ JSBool ok;
+ jsval val;
+
+/*
+ * Local macros
+ */
+#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb)) return JS_FALSE
+#define POP_STR() OFF2STR(&ss->sprinter, PopOff(ss, op))
+#define LOCAL_ASSERT(expr) JS_ASSERT(expr); if (!(expr)) return JS_FALSE
+
+/*
+ * Get atom from script's atom map, quote/escape its string appropriately into
+ * rval, and select fmt from the quoted and unquoted alternatives.
+ */
+#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \
+ JS_BEGIN_MACRO \
+ jschar quote_; \
+ atom = GET_ATOM(cx, jp->script, pc); \
+ if (ATOM_KEYWORD(atom)) { \
+ quote_ = '\''; \
+ fmt = qfmt; \
+ } else { \
+ quote_ = 0; \
+ fmt = ufmt; \
+ } \
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), quote_); \
+ if (!rval) \
+ return JS_FALSE; \
+ JS_END_MACRO
+
+ cx = ss->sprinter.context;
+ jp = ss->printer;
+ endpc = pc + nb;
+ forelem_tail = forelem_done = NULL;
+ todo = -2; /* NB: different from Sprint() error return. */
+ tail = -1;
+ op = JSOP_NOP;
+ sn = NULL;
+ rval = NULL;
+
+ while (pc < endpc) {
+ lastop = op;
+ op = saveop = (JSOp) *pc;
+ if (op >= JSOP_LIMIT) {
+ switch (op) {
+ case JSOP_GETPROP2:
+ saveop = JSOP_GETPROP;
+ break;
+ case JSOP_GETELEM2:
+ saveop = JSOP_GETELEM;
+ break;
+ default:;
+ }
+ }
+ cs = &js_CodeSpec[saveop];
+ len = oplen = cs->length;
+
+ if (cs->token) {
+ switch (cs->nuses) {
+ case 2:
+ rval = POP_STR();
+ lval = POP_STR();
+ sn = js_GetSrcNote(jp->script, pc);
+ if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {
+ /* Print only the right operand of the assignment-op. */
+ todo = SprintPut(&ss->sprinter, rval, strlen(rval));
+ } else {
+ todo = Sprint(&ss->sprinter, "%s %s %s",
+ lval, cs->token, rval);
+ }
+ break;
+
+ case 1:
+ rval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s%s", cs->token, rval);
+ break;
+
+ case 0:
+#if JS_HAS_GETTER_SETTER
+ if (op == JSOP_GETTER || op == JSOP_SETTER) {
+ todo = -2;
+ break;
+ }
+#endif
+ todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token));
+ break;
+
+ default:
+ todo = -2;
+ break;
+ }
+ } else {
+ switch (op) {
+ case JSOP_NOP:
+ /*
+ * Check for a do-while loop, a for-loop with an empty
+ * initializer part, a labeled statement, a function
+ * definition, or try/finally.
+ */
+ sn = js_GetSrcNote(jp->script, pc);
+ todo = -2;
+ switch (sn ? SN_TYPE(sn) : SRC_NULL) {
+#if JS_HAS_DO_WHILE_LOOP
+ case SRC_WHILE:
+ js_printf(jp, "\tdo {\n");
+ jp->indent += 4;
+ break;
+#endif /* JS_HAS_DO_WHILE_LOOP */
+
+ case SRC_FOR:
+ rval = "";
+
+ do_forloop:
+ /* Skip the JSOP_NOP or JSOP_POP bytecode. */
+ pc++;
+
+ /* Get the cond, next, and loop-closing tail offsets. */
+ cond = js_GetSrcNoteOffset(sn, 0);
+ next = js_GetSrcNoteOffset(sn, 1);
+ tail = js_GetSrcNoteOffset(sn, 2);
+ LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == 0);
+
+ /* Print the keyword and the possibly empty init-part. */
+ js_printf(jp, "\tfor (%s;", rval);
+
+ if (pc[cond] == JSOP_IFEQ || pc[cond] == JSOP_IFEQX) {
+ /* Decompile the loop condition. */
+ DECOMPILE_CODE(pc, cond);
+ js_printf(jp, " %s", POP_STR());
+ }
+
+ /* Need a semicolon whether or not there was a cond. */
+ js_puts(jp, ";");
+
+ if (pc[next] != JSOP_GOTO && pc[next] != JSOP_GOTOX) {
+ /* Decompile the loop updater. */
+ DECOMPILE_CODE(pc + next, tail - next - 1);
+ js_printf(jp, " %s", POP_STR());
+ }
+
+ /* Do the loop body. */
+ js_puts(jp, ") {\n");
+ jp->indent += 4;
+ oplen = (cond) ? js_CodeSpec[pc[cond]].length : 0;
+ DECOMPILE_CODE(pc + cond + oplen, next - cond - oplen);
+ jp->indent -= 4;
+ js_printf(jp, "\t}\n");
+
+ /* Set len so pc skips over the entire loop. */
+ len = tail + js_CodeSpec[pc[tail]].length;
+ break;
+
+ case SRC_LABEL:
+ atom = js_GetAtom(cx, &jp->script->atomMap,
+ (jsatomid) js_GetSrcNoteOffset(sn, 0));
+ jp->indent -= 4;
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ js_printf(jp, "\t%s:\n", rval);
+ jp->indent += 4;
+ break;
+
+ case SRC_LABELBRACE:
+ atom = js_GetAtom(cx, &jp->script->atomMap,
+ (jsatomid) js_GetSrcNoteOffset(sn, 0));
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ js_printf(jp, "\t%s: {\n", rval);
+ jp->indent += 4;
+ break;
+
+ case SRC_ENDBRACE:
+ jp->indent -= 4;
+ js_printf(jp, "\t}\n");
+ break;
+
+ case SRC_CATCH:
+ jp->indent -= 4;
+ sn = js_GetSrcNote(jp->script, pc);
+ pc += oplen;
+ js_printf(jp, "\t} catch (");
+
+ LOCAL_ASSERT(*pc == JSOP_NAME);
+ pc += js_CodeSpec[JSOP_NAME].length;
+ LOCAL_ASSERT(*pc == JSOP_PUSHOBJ);
+ pc += js_CodeSpec[JSOP_PUSHOBJ].length;
+ LOCAL_ASSERT(*pc == JSOP_NEWINIT);
+ pc += js_CodeSpec[JSOP_NEWINIT].length;
+ LOCAL_ASSERT(*pc == JSOP_EXCEPTION);
+ pc += js_CodeSpec[JSOP_EXCEPTION].length;
+ LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR);
+ atom = GET_ATOM(cx, jp->script, pc);
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ js_printf(jp, "%s", rval);
+ pc += js_CodeSpec[JSOP_INITCATCHVAR].length;
+ LOCAL_ASSERT(*pc == JSOP_ENTERWITH);
+ pc += js_CodeSpec[JSOP_ENTERWITH].length;
+
+ len = js_GetSrcNoteOffset(sn, 0);
+ if (len) {
+ js_printf(jp, " if ");
+ DECOMPILE_CODE(pc, len);
+ js_printf(jp, "%s", POP_STR());
+ pc += len;
+ LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);
+ pc += js_CodeSpec[*pc].length;
+ }
+
+ js_printf(jp, ") {\n");
+ jp->indent += 4;
+ len = 0;
+ break;
+
+ case SRC_FUNCDEF:
+ atom = js_GetAtom(cx, &jp->script->atomMap,
+ (jsatomid) js_GetSrcNoteOffset(sn, 0));
+ JS_ASSERT(ATOM_IS_OBJECT(atom));
+ do_function:
+ obj = ATOM_TO_OBJECT(atom);
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
+ jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun),
+ jp->indent, jp->pretty);
+ if (!jp2)
+ return JS_FALSE;
+ jp2->scope = jp->scope;
+ if (js_DecompileFunction(jp2, fun)) {
+ str = js_GetPrinterOutput(jp2);
+ if (str)
+ js_printf(jp, "%s\n", JS_GetStringBytes(str));
+ }
+ js_DestroyPrinter(jp2);
+ break;
+
+ default:;
+ }
+ case JSOP_RETRVAL:
+ break;
+
+ case JSOP_GROUP:
+ /* Use last real op so PopOff adds parens if needed. */
+ todo = PopOff(ss, lastop);
+
+ /* Now add user-supplied parens only if PopOff did not. */
+ cs = &js_CodeSpec[lastop];
+ topcs = &js_CodeSpec[ss->opcodes[ss->top]];
+ if (topcs->prec >= cs->prec) {
+ todo = Sprint(&ss->sprinter, "(%s)",
+ OFF2STR(&ss->sprinter, todo));
+ }
+ break;
+
+ case JSOP_PUSH:
+ case JSOP_PUSHOBJ:
+ case JSOP_BINDNAME:
+ todo = Sprint(&ss->sprinter, "");
+ break;
+
+#if JS_HAS_EXCEPTIONS
+ case JSOP_TRY:
+ js_printf(jp, "\ttry {\n");
+ jp->indent += 4;
+ todo = -2;
+ break;
+
+ {
+ static const char finally_cookie[] = "finally-cookie";
+
+ case JSOP_FINALLY:
+ jp->indent -= 4;
+ js_printf(jp, "\t} finally {\n");
+ jp->indent += 4;
+
+ /*
+ * We must push an empty string placeholder for gosub's return
+ * address, popped by JSOP_RETSUB and counted by script->depth
+ * but not by ss->top (see JSOP_SETSP, below).
+ */
+ todo = Sprint(&ss->sprinter, finally_cookie);
+ break;
+
+ case JSOP_RETSUB:
+ rval = POP_STR();
+ LOCAL_ASSERT(strcmp(rval, finally_cookie) == 0);
+ todo = -2;
+ break;
+ }
+
+ case JSOP_SWAP:
+ /*
+ * We don't generate this opcode currently, and previously we
+ * did not need to decompile it. If old, serialized bytecode
+ * uses it still, we should fall through and set todo = -2.
+ */
+ /* FALL THROUGH */
+
+ case JSOP_GOSUB:
+ case JSOP_GOSUBX:
+ /*
+ * JSOP_GOSUB and GOSUBX have no effect on the decompiler's
+ * string stack because the next op in bytecode order finds
+ * the stack balanced by a JSOP_RETSUB executed elsewhere.
+ */
+ todo = -2;
+ break;
+
+ case JSOP_SETSP:
+ /*
+ * The compiler models operand stack depth and fixes the stack
+ * pointer on entry to a catch clause based on its depth model.
+ * The decompiler must match the code generator's model, which
+ * is why JSOP_FINALLY pushes a cookie that JSOP_RETSUB pops.
+ */
+ ss->top = (uintN) GET_ATOM_INDEX(pc);
+ break;
+
+ case JSOP_EXCEPTION:
+ /*
+ * The only other JSOP_EXCEPTION case occurs as part of a code
+ * sequence that follows a SRC_CATCH-annotated JSOP_NOP.
+ */
+ sn = js_GetSrcNote(jp->script, pc);
+ LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_HIDDEN);
+ todo = -2;
+ break;
+#endif /* JS_HAS_EXCEPTIONS */
+
+ case JSOP_POP:
+ case JSOP_POPV:
+ sn = js_GetSrcNote(jp->script, pc);
+ switch (sn ? SN_TYPE(sn) : SRC_NULL) {
+ case SRC_FOR:
+ rval = POP_STR();
+ todo = -2;
+ goto do_forloop;
+
+ case SRC_PCDELTA:
+ /* Pop and save to avoid blowing stack depth budget. */
+ lval = JS_strdup(cx, POP_STR());
+ if (!lval)
+ return JS_FALSE;
+
+ /*
+ * The offset tells distance to the end of the right-hand
+ * operand of the comma operator.
+ */
+ done = pc + len;
+ pc += js_GetSrcNoteOffset(sn, 0);
+ len = 0;
+
+ if (!Decompile(ss, done, pc - done)) {
+ JS_free(cx, (char *)lval);
+ return JS_FALSE;
+ }
+
+ /* Pop Decompile result and print comma expression. */
+ rval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s, %s", lval, rval);
+ JS_free(cx, (char *)lval);
+ break;
+
+ case SRC_HIDDEN:
+ /* Hide this pop, it's from a goto in a with or for/in. */
+ todo = -2;
+ break;
+
+ default:
+ rval = POP_STR();
+ if (*rval != '\0')
+ js_printf(jp, "\t%s;\n", rval);
+ todo = -2;
+ break;
+ }
+ break;
+
+ case JSOP_POP2:
+ (void) PopOff(ss, op);
+ (void) PopOff(ss, op);
+ todo = -2;
+ break;
+
+ {
+ static const char with_cookie[] = "with-cookie";
+
+ case JSOP_ENTERWITH:
+ sn = js_GetSrcNote(jp->script, pc);
+ if (sn && SN_TYPE(sn) == SRC_HIDDEN) {
+ todo = -2;
+ break;
+ }
+ rval = POP_STR();
+ js_printf(jp, "\twith (%s) {\n", rval);
+ jp->indent += 4;
+ todo = Sprint(&ss->sprinter, with_cookie);
+ break;
+
+ case JSOP_LEAVEWITH:
+ sn = js_GetSrcNote(jp->script, pc);
+ todo = -2;
+ if (sn && SN_TYPE(sn) == SRC_HIDDEN)
+ break;
+ rval = POP_STR();
+ LOCAL_ASSERT(strcmp(rval, with_cookie) == 0);
+ jp->indent -= 4;
+ js_printf(jp, "\t}\n");
+ break;
+ }
+
+ case JSOP_SETRVAL:
+ case JSOP_RETURN:
+ rval = POP_STR();
+ if (*rval != '\0')
+ js_printf(jp, "\t%s %s;\n", cs->name, rval);
+ else
+ js_printf(jp, "\t%s;\n", cs->name);
+ todo = -2;
+ break;
+
+#if JS_HAS_EXCEPTIONS
+ case JSOP_THROW:
+ sn = js_GetSrcNote(jp->script, pc);
+ todo = -2;
+ if (sn && SN_TYPE(sn) == SRC_HIDDEN)
+ break;
+ rval = POP_STR();
+ js_printf(jp, "\t%s %s;\n", cs->name, rval);
+ break;
+#endif /* JS_HAS_EXCEPTIONS */
+
+ case JSOP_GOTO:
+ case JSOP_GOTOX:
+ sn = js_GetSrcNote(jp->script, pc);
+ switch (sn ? SN_TYPE(sn) : SRC_NULL) {
+ case SRC_CONT2LABEL:
+ atom = js_GetAtom(cx, &jp->script->atomMap,
+ (jsatomid) js_GetSrcNoteOffset(sn, 0));
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ js_printf(jp, "\tcontinue %s;\n", rval);
+ break;
+ case SRC_CONTINUE:
+ js_printf(jp, "\tcontinue;\n");
+ break;
+ case SRC_BREAK2LABEL:
+ atom = js_GetAtom(cx, &jp->script->atomMap,
+ (jsatomid) js_GetSrcNoteOffset(sn, 0));
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ js_printf(jp, "\tbreak %s;\n", rval);
+ break;
+ case SRC_HIDDEN:
+ break;
+ default:
+ js_printf(jp, "\tbreak;\n");
+ break;
+ }
+ todo = -2;
+ break;
+
+ case JSOP_IFEQ:
+ case JSOP_IFEQX:
+ len = GetJumpOffset(pc, pc);
+ sn = js_GetSrcNote(jp->script, pc);
+
+ switch (sn ? SN_TYPE(sn) : SRC_NULL) {
+ case SRC_IF:
+ case SRC_IF_ELSE:
+ rval = POP_STR();
+ js_printf(jp, "\tif (%s) {\n", rval);
+ jp->indent += 4;
+ if (SN_TYPE(sn) == SRC_IF) {
+ DECOMPILE_CODE(pc + oplen, len - oplen);
+ } else {
+ len = js_GetSrcNoteOffset(sn, 0);
+ DECOMPILE_CODE(pc + oplen, len - oplen);
+ jp->indent -= 4;
+ pc += len;
+ LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
+ oplen = js_CodeSpec[*pc].length;
+ len = GetJumpOffset(pc, pc);
+ js_printf(jp, "\t} else {\n");
+ jp->indent += 4;
+ DECOMPILE_CODE(pc + oplen, len - oplen);
+ }
+ jp->indent -= 4;
+ js_printf(jp, "\t}\n");
+ todo = -2;
+ break;
+
+ case SRC_WHILE:
+ rval = POP_STR();
+ js_printf(jp, "\twhile (%s) {\n", rval);
+ jp->indent += 4;
+ tail = js_GetSrcNoteOffset(sn, 0);
+ DECOMPILE_CODE(pc + oplen, tail - oplen);
+ jp->indent -= 4;
+ js_printf(jp, "\t}\n");
+ todo = -2;
+ break;
+
+ case SRC_COND:
+ xval = JS_strdup(cx, POP_STR());
+ if (!xval)
+ return JS_FALSE;
+ len = js_GetSrcNoteOffset(sn, 0);
+ DECOMPILE_CODE(pc + oplen, len - oplen);
+ lval = JS_strdup(cx, POP_STR());
+ if (!lval) {
+ JS_free(cx, (void *)xval);
+ return JS_FALSE;
+ }
+ pc += len;
+ LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
+ oplen = js_CodeSpec[*pc].length;
+ len = GetJumpOffset(pc, pc);
+ DECOMPILE_CODE(pc + oplen, len - oplen);
+ rval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s ? %s : %s",
+ xval, lval, rval);
+ JS_free(cx, (void *)xval);
+ JS_free(cx, (void *)lval);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case JSOP_IFNE:
+ case JSOP_IFNEX:
+#if JS_HAS_DO_WHILE_LOOP
+ /* Currently, this must be a do-while loop's upward branch. */
+ jp->indent -= 4;
+ js_printf(jp, "\t} while (%s);\n", POP_STR());
+ todo = -2;
+#else
+ JS_ASSERT(0);
+#endif /* JS_HAS_DO_WHILE_LOOP */
+ break;
+
+ case JSOP_OR:
+ case JSOP_ORX:
+ xval = "||";
+
+ do_logical_connective:
+ /* Top of stack is the first clause in a disjunction (||). */
+ lval = JS_strdup(cx, POP_STR());
+ if (!lval)
+ return JS_FALSE;
+ done = pc + GetJumpOffset(pc, pc);
+ pc += len;
+ len = PTRDIFF(done, pc, jsbytecode);
+ DECOMPILE_CODE(pc, len);
+ rval = POP_STR();
+ if (jp->pretty &&
+ jp->indent + 4 + strlen(lval) + 4 + strlen(rval) > 75) {
+ rval = JS_strdup(cx, rval);
+ if (!rval) {
+ tail = -1;
+ } else {
+ todo = Sprint(&ss->sprinter, "%s %s\n", lval, xval);
+ tail = Sprint(&ss->sprinter, "%*s%s",
+ jp->indent + 4, "", rval);
+ JS_free(cx, (char *)rval);
+ }
+ if (tail < 0)
+ todo = -1;
+ } else {
+ todo = Sprint(&ss->sprinter, "%s %s %s", lval, xval, rval);
+ }
+ JS_free(cx, (char *)lval);
+ break;
+
+ case JSOP_AND:
+ case JSOP_ANDX:
+ xval = "&&";
+ goto do_logical_connective;
+
+ case JSOP_FORARG:
+ atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_fornameinloop;
+
+ case JSOP_FORVAR:
+ atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_fornameinloop;
+
+ case JSOP_FORNAME:
+ atom = GET_ATOM(cx, jp->script, pc);
+
+ do_fornameinloop:
+ sn = js_GetSrcNote(jp->script, pc);
+ xval = NULL;
+ lval = "";
+ goto do_forinloop;
+
+ case JSOP_FORPROP:
+ xval = NULL;
+ atom = GET_ATOM(cx, jp->script, pc);
+ if (ATOM_KEYWORD(atom)) {
+ xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
+ (jschar)'\'');
+ if (!xval)
+ return JS_FALSE;
+ atom = NULL;
+ }
+ lval = POP_STR();
+ sn = NULL;
+
+ do_forinloop:
+ pc += oplen;
+ LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);
+ oplen = js_CodeSpec[*pc].length;
+ len = GetJumpOffset(pc, pc);
+ sn2 = js_GetSrcNote(jp->script, pc);
+ tail = js_GetSrcNoteOffset(sn2, 0);
+
+ do_forinbody:
+ js_printf(jp, "\tfor (%s%s", VarPrefix(sn), lval);
+ if (atom) {
+ xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!xval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, xval);
+ js_printf(jp, *lval ? ".%s" : "%s", xval);
+ } else if (xval) {
+ js_printf(jp, "[%s]", xval);
+ }
+ rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]);
+ js_printf(jp, " in %s) {\n", rval);
+ jp->indent += 4;
+ DECOMPILE_CODE(pc + oplen, tail - oplen);
+ jp->indent -= 4;
+ js_printf(jp, "\t}\n");
+ todo = -2;
+ break;
+
+ case JSOP_FORELEM:
+ pc++;
+ LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);
+ len = js_CodeSpec[*pc].length;
+
+ /*
+ * Arrange for the JSOP_ENUMELEM case to set tail for use by
+ * do_forinbody: code that uses on it to find the loop-closing
+ * jump (whatever its format, normal or extended), in order to
+ * bound the recursively decompiled loop body.
+ */
+ sn = js_GetSrcNote(jp->script, pc);
+ JS_ASSERT(!forelem_tail);
+ forelem_tail = pc + js_GetSrcNoteOffset(sn, 0);
+
+ /*
+ * This gets a little wacky. Only the length of the for loop
+ * body PLUS the element-indexing expression is known here, so
+ * we pass the after-loop pc to the JSOP_ENUMELEM case, which
+ * is immediately below, to decompile that helper bytecode via
+ * the 'forelem_done' local.
+ *
+ * Since a for..in loop can't nest in the head of another for
+ * loop, we can use forelem_{tail,done} singletons to remember
+ * state from JSOP_FORELEM to JSOP_ENUMELEM, thence (via goto)
+ * to label do_forinbody.
+ */
+ JS_ASSERT(!forelem_done);
+ forelem_done = pc + GetJumpOffset(pc, pc);
+ break;
+
+ case JSOP_ENUMELEM:
+ /*
+ * The stack has the object under the (top) index expression.
+ * The "rval" property id is underneath those two on the stack.
+ * The for loop body net and gross lengths can now be adjusted
+ * to account for the length of the indexing expression that
+ * came after JSOP_FORELEM and before JSOP_ENUMELEM.
+ */
+ atom = NULL;
+ xval = POP_STR();
+ lval = POP_STR();
+ rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]);
+ JS_ASSERT(forelem_tail > pc);
+ tail = forelem_tail - pc;
+ forelem_tail = NULL;
+ JS_ASSERT(forelem_done > pc);
+ len = forelem_done - pc;
+ forelem_done = NULL;
+ goto do_forinbody;
+
+ case JSOP_DUP2:
+ rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-2]);
+ todo = SprintPut(&ss->sprinter, rval, strlen(rval));
+ if (todo < 0 || !PushOff(ss, todo, ss->opcodes[ss->top-2]))
+ return JS_FALSE;
+ /* FALL THROUGH */
+
+ case JSOP_DUP:
+ rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]);
+ op = ss->opcodes[ss->top-1];
+ todo = SprintPut(&ss->sprinter, rval, strlen(rval));
+ break;
+
+ case JSOP_SETARG:
+ atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_setname;
+
+ case JSOP_SETVAR:
+ atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_setname;
+
+ case JSOP_SETCONST:
+ case JSOP_SETNAME:
+ atom = GET_ATOM(cx, jp->script, pc);
+ do_setname:
+ lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!lval)
+ return JS_FALSE;
+ rval = POP_STR();
+ if (op == JSOP_SETNAME)
+ (void) PopOff(ss, op);
+ do_setlval:
+ sn = js_GetSrcNote(jp->script, pc - 1);
+ if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {
+ todo = Sprint(&ss->sprinter, "%s %s= %s",
+ lval, js_CodeSpec[lastop].token, rval);
+ } else {
+ sn = js_GetSrcNote(jp->script, pc);
+ todo = Sprint(&ss->sprinter, "%s%s = %s",
+ VarPrefix(sn), lval, rval);
+ }
+ break;
+
+ case JSOP_NEW:
+ case JSOP_CALL:
+ case JSOP_EVAL:
+#if JS_HAS_LVALUE_RETURN
+ case JSOP_SETCALL:
+#endif
+ saveop = op;
+ op = JSOP_NOP; /* turn off parens */
+ argc = GET_ARGC(pc);
+ argv = (char **)
+ JS_malloc(cx, (size_t)(argc + 1) * sizeof *argv);
+ if (!argv)
+ return JS_FALSE;
+
+ ok = JS_TRUE;
+ for (i = argc; i > 0; i--) {
+ argv[i] = JS_strdup(cx, POP_STR());
+ if (!argv[i]) {
+ ok = JS_FALSE;
+ break;
+ }
+ }
+
+ /* Skip the JSOP_PUSHOBJ-created empty string. */
+ LOCAL_ASSERT(ss->top >= 2);
+ (void) PopOff(ss, op);
+
+ /* Get the callee's decompiled image in argv[0]. */
+ argv[0] = JS_strdup(cx, POP_STR());
+ if (!argv[i])
+ ok = JS_FALSE;
+
+ lval = "(", rval = ")";
+ if (saveop == JSOP_NEW) {
+ todo = Sprint(&ss->sprinter, "%s %s%s",
+ js_new_str, argv[0], lval);
+ } else {
+ todo = Sprint(&ss->sprinter, "%s%s",
+ argv[0], lval);
+ }
+ if (todo < 0)
+ ok = JS_FALSE;
+
+ for (i = 1; i <= argc; i++) {
+ if (!argv[i] ||
+ Sprint(&ss->sprinter, "%s%s",
+ argv[i], (i < argc) ? ", " : "") < 0) {
+ ok = JS_FALSE;
+ break;
+ }
+ }
+ if (Sprint(&ss->sprinter, rval) < 0)
+ ok = JS_FALSE;
+
+ for (i = 0; i <= argc; i++) {
+ if (argv[i])
+ JS_free(cx, argv[i]);
+ }
+ JS_free(cx, argv);
+ if (!ok)
+ return JS_FALSE;
+ op = saveop;
+#if JS_HAS_LVALUE_RETURN
+ if (op == JSOP_SETCALL) {
+ if (!PushOff(ss, todo, op))
+ return JS_FALSE;
+ todo = Sprint(&ss->sprinter, "");
+ }
+#endif
+ break;
+
+ case JSOP_DELNAME:
+ atom = GET_ATOM(cx, jp->script, pc);
+ lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!lval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, lval);
+ todo = Sprint(&ss->sprinter, "%s %s", js_delete_str, lval);
+ break;
+
+ case JSOP_DELPROP:
+ GET_ATOM_QUOTE_AND_FMT("%s %s[%s]", "%s %s.%s", rval);
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, fmt, js_delete_str, lval, rval);
+ break;
+
+ case JSOP_DELELEM:
+ xval = POP_STR();
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s %s[%s]",
+ js_delete_str, lval, xval);
+ break;
+
+ case JSOP_TYPEOF:
+ case JSOP_VOID:
+ rval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s %s", cs->name, rval);
+ break;
+
+ case JSOP_INCARG:
+ case JSOP_DECARG:
+ atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_incatom;
+
+ case JSOP_INCVAR:
+ case JSOP_DECVAR:
+ atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_incatom;
+
+ case JSOP_INCNAME:
+ case JSOP_DECNAME:
+ atom = GET_ATOM(cx, jp->script, pc);
+ do_incatom:
+ lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!lval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, lval);
+ todo = Sprint(&ss->sprinter, "%s%s",
+ js_incop_str[!(cs->format & JOF_INC)], lval);
+ break;
+
+ case JSOP_INCPROP:
+ case JSOP_DECPROP:
+ GET_ATOM_QUOTE_AND_FMT("%s%s[%s]", "%s%s.%s", rval);
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, fmt,
+ js_incop_str[!(cs->format & JOF_INC)],
+ lval, rval);
+ break;
+
+ case JSOP_INCELEM:
+ case JSOP_DECELEM:
+ xval = POP_STR();
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s%s[%s]",
+ js_incop_str[!(cs->format & JOF_INC)],
+ lval, xval);
+ break;
+
+ case JSOP_ARGINC:
+ case JSOP_ARGDEC:
+ atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_atominc;
+
+ case JSOP_VARINC:
+ case JSOP_VARDEC:
+ atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_atominc;
+
+ case JSOP_NAMEINC:
+ case JSOP_NAMEDEC:
+ atom = GET_ATOM(cx, jp->script, pc);
+ do_atominc:
+ lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!lval)
+ return JS_FALSE;
+ todo = STR2OFF(&ss->sprinter, lval);
+ SprintPut(&ss->sprinter,
+ js_incop_str[!(cs->format & JOF_INC)],
+ 2);
+ break;
+
+ case JSOP_PROPINC:
+ case JSOP_PROPDEC:
+ GET_ATOM_QUOTE_AND_FMT("%s[%s]%s", "%s.%s%s", rval);
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, fmt, lval, rval,
+ js_incop_str[!(cs->format & JOF_INC)]);
+ break;
+
+ case JSOP_ELEMINC:
+ case JSOP_ELEMDEC:
+ xval = POP_STR();
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s[%s]%s",
+ lval, xval,
+ js_incop_str[!(cs->format & JOF_INC)]);
+ break;
+
+ case JSOP_GETPROP2:
+ op = JSOP_GETPROP;
+ (void) PopOff(ss, lastop);
+ /* FALL THROUGH */
+
+ case JSOP_GETPROP:
+ GET_ATOM_QUOTE_AND_FMT("%s[%s]", "%s.%s", rval);
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, fmt, lval, rval);
+ break;
+
+ case JSOP_SETPROP:
+ GET_ATOM_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval);
+ rval = POP_STR();
+ lval = POP_STR();
+ sn = js_GetSrcNote(jp->script, pc - 1);
+ todo = Sprint(&ss->sprinter, fmt, lval, xval,
+ (sn && SN_TYPE(sn) == SRC_ASSIGNOP)
+ ? js_CodeSpec[lastop].token
+ : "",
+ rval);
+ break;
+
+ case JSOP_GETELEM2:
+ op = JSOP_GETELEM;
+ (void) PopOff(ss, lastop);
+ /* FALL THROUGH */
+
+ case JSOP_GETELEM:
+ op = JSOP_NOP; /* turn off parens */
+ xval = POP_STR();
+ op = JSOP_GETELEM;
+ lval = POP_STR();
+ if (*xval == '\0')
+ todo = Sprint(&ss->sprinter, "%s", lval);
+ else
+ todo = Sprint(&ss->sprinter, "%s[%s]", lval, xval);
+ break;
+
+ case JSOP_SETELEM:
+ op = JSOP_NOP; /* turn off parens */
+ rval = POP_STR();
+ xval = POP_STR();
+ op = JSOP_SETELEM;
+ lval = POP_STR();
+ if (*xval == '\0')
+ goto do_setlval;
+ sn = js_GetSrcNote(jp->script, pc - 1);
+ todo = Sprint(&ss->sprinter, "%s[%s] %s= %s",
+ lval, xval,
+ (sn && SN_TYPE(sn) == SRC_ASSIGNOP)
+ ? js_CodeSpec[lastop].token
+ : "",
+ rval);
+ break;
+
+ case JSOP_ARGSUB:
+ i = (jsint) GET_ATOM_INDEX(pc);
+ todo = Sprint(&ss->sprinter, "%s[%d]",
+ js_arguments_str, (int) i);
+ break;
+
+ case JSOP_ARGCNT:
+ todo = Sprint(&ss->sprinter, "%s.%s",
+ js_arguments_str, js_length_str);
+ break;
+
+ case JSOP_GETARG:
+ atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_name;
+
+ case JSOP_GETVAR:
+ atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
+ LOCAL_ASSERT(atom);
+ goto do_name;
+
+ case JSOP_NAME:
+ atom = GET_ATOM(cx, jp->script, pc);
+ do_name:
+ sn = js_GetSrcNote(jp->script, pc);
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ todo = Sprint(&ss->sprinter, "%s%s", VarPrefix(sn), rval);
+ break;
+
+ case JSOP_UINT16:
+ i = (jsint) GET_ATOM_INDEX(pc);
+ todo = Sprint(&ss->sprinter, "%u", (unsigned) i);
+ break;
+
+ case JSOP_NUMBER:
+ atom = GET_ATOM(cx, jp->script, pc);
+ val = ATOM_KEY(atom);
+ if (JSVAL_IS_INT(val)) {
+ long ival = (long)JSVAL_TO_INT(val);
+ todo = Sprint(&ss->sprinter, "%ld", ival);
+ } else {
+ char buf[DTOSTR_STANDARD_BUFFER_SIZE];
+ char *numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD,
+ 0, *JSVAL_TO_DOUBLE(val));
+ if (!numStr) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ todo = Sprint(&ss->sprinter, numStr);
+ }
+ break;
+
+ case JSOP_STRING:
+ atom = GET_ATOM(cx, jp->script, pc);
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
+ (jschar)'"');
+ if (!rval)
+ return JS_FALSE;
+ todo = STR2OFF(&ss->sprinter, rval);
+ break;
+
+ case JSOP_OBJECT:
+ case JSOP_ANONFUNOBJ:
+ case JSOP_NAMEDFUNOBJ:
+ atom = GET_ATOM(cx, jp->script, pc);
+ if (op == JSOP_OBJECT) {
+ str = js_ValueToSource(cx, ATOM_KEY(atom));
+ if (!str)
+ return JS_FALSE;
+ } else {
+ if (!js_fun_toString(cx, ATOM_TO_OBJECT(atom),
+ JS_DONT_PRETTY_PRINT, 0, NULL,
+ &val)) {
+ return JS_FALSE;
+ }
+ str = JSVAL_TO_STRING(val);
+ }
+ todo = SprintPut(&ss->sprinter, JS_GetStringBytes(str),
+ JSSTRING_LENGTH(str));
+ break;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case JSOP_TABLESWITCH:
+ case JSOP_TABLESWITCHX:
+ {
+ jsbytecode *pc2;
+ ptrdiff_t off, off2;
+ jsint j, n, low, high;
+ TableEntry *table;
+
+ sn = js_GetSrcNote(jp->script, pc);
+ JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
+ len = js_GetSrcNoteOffset(sn, 0);
+ pc2 = pc;
+ off = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ low = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ high = GetJumpOffset(pc, pc2);
+
+ n = high - low + 1;
+ if (n == 0) {
+ table = NULL;
+ j = 0;
+ } else {
+ table = (TableEntry *)
+ JS_malloc(cx, (size_t)n * sizeof *table);
+ if (!table)
+ return JS_FALSE;
+ for (i = j = 0; i < n; i++) {
+ pc2 += JUMP_OFFSET_LEN;
+ off2 = GetJumpOffset(pc, pc2);
+ if (off2) {
+ table[j].key = INT_TO_JSVAL(low + i);
+ table[j++].offset = off2;
+ }
+ }
+ js_HeapSort(table, (size_t) j, sizeof *table,
+ CompareOffsets, NULL);
+ }
+
+ ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off,
+ JS_FALSE);
+ JS_free(cx, table);
+ if (!ok)
+ return ok;
+ todo = -2;
+ break;
+ }
+
+ case JSOP_LOOKUPSWITCH:
+ case JSOP_LOOKUPSWITCHX:
+ {
+ jsbytecode *pc2;
+ ptrdiff_t off, off2;
+ jsint npairs;
+ TableEntry *table;
+
+ sn = js_GetSrcNote(jp->script, pc);
+ JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
+ len = js_GetSrcNoteOffset(sn, 0);
+ pc2 = pc;
+ off = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ npairs = (jsint) GET_ATOM_INDEX(pc2);
+ pc2 += ATOM_INDEX_LEN;
+
+ table = (TableEntry *)
+ JS_malloc(cx, (size_t)npairs * sizeof *table);
+ if (!table)
+ return JS_FALSE;
+ for (i = 0; i < npairs; i++) {
+ atom = GET_ATOM(cx, jp->script, pc2);
+ pc2 += ATOM_INDEX_LEN;
+ off2 = GetJumpOffset(pc, pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ table[i].key = ATOM_KEY(atom);
+ table[i].offset = off2;
+ }
+
+ ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off,
+ JS_FALSE);
+ JS_free(cx, table);
+ if (!ok)
+ return ok;
+ todo = -2;
+ break;
+ }
+
+ case JSOP_CONDSWITCH:
+ {
+ jsbytecode *pc2;
+ ptrdiff_t off, off2, caseOff;
+ jsint ncases;
+ TableEntry *table;
+
+ sn = js_GetSrcNote(jp->script, pc);
+ JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
+ len = js_GetSrcNoteOffset(sn, 0);
+ off = js_GetSrcNoteOffset(sn, 1);
+
+ /*
+ * Count the cases using offsets from switch to first case,
+ * and case to case, stored in srcnote immediates.
+ */
+ pc2 = pc;
+ off2 = off;
+ for (ncases = 0; off2 != 0; ncases++) {
+ pc2 += off2;
+ JS_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT ||
+ *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX);
+ if (*pc2 == JSOP_DEFAULT || *pc2 == JSOP_DEFAULTX) {
+ /* End of cases, but count default as a case. */
+ off2 = 0;
+ } else {
+ sn = js_GetSrcNote(jp->script, pc2);
+ JS_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA);
+ off2 = js_GetSrcNoteOffset(sn, 0);
+ }
+ }
+
+ /*
+ * Allocate table and rescan the cases using their srcnotes,
+ * stashing each case's delta from switch top in table[i].key,
+ * and the distance to its statements in table[i].offset.
+ */
+ table = (TableEntry *)
+ JS_malloc(cx, (size_t)ncases * sizeof *table);
+ if (!table)
+ return JS_FALSE;
+ pc2 = pc;
+ off2 = off;
+ for (i = 0; i < ncases; i++) {
+ pc2 += off2;
+ JS_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT ||
+ *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX);
+ caseOff = pc2 - pc;
+ table[i].key = INT_TO_JSVAL((jsint) caseOff);
+ table[i].offset = caseOff + GetJumpOffset(pc2, pc2);
+ if (*pc2 == JSOP_CASE || *pc2 == JSOP_CASEX) {
+ sn = js_GetSrcNote(jp->script, pc2);
+ JS_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA);
+ off2 = js_GetSrcNoteOffset(sn, 0);
+ }
+ }
+
+ /*
+ * Find offset of default code by fetching the default offset
+ * from the end of table. JSOP_CONDSWITCH always has a default
+ * case at the end.
+ */
+ off = JSVAL_TO_INT(table[ncases-1].key);
+ pc2 = pc + off;
+ off += GetJumpOffset(pc2, pc2);
+
+ ok = DecompileSwitch(ss, table, (uintN)ncases, pc, len, off,
+ JS_TRUE);
+ JS_free(cx, table);
+ if (!ok)
+ return ok;
+ todo = -2;
+ break;
+ }
+
+ case JSOP_CASE:
+ case JSOP_CASEX:
+ {
+ lval = POP_STR();
+ if (!lval)
+ return JS_FALSE;
+ js_printf(jp, "\tcase %s:\n", lval);
+ todo = -2;
+ break;
+ }
+
+#endif /* JS_HAS_SWITCH_STATEMENT */
+
+#if !JS_BUG_FALLIBLE_EQOPS
+ case JSOP_NEW_EQ:
+ case JSOP_NEW_NE:
+ rval = POP_STR();
+ lval = POP_STR();
+ todo = Sprint(&ss->sprinter, "%s %c%s %s",
+ lval,
+ (op == JSOP_NEW_EQ) ? '=' : '!',
+#if JS_HAS_TRIPLE_EQOPS
+ JSVERSION_IS_ECMA(cx->version) ? "==" :
+#endif
+ "=",
+ rval);
+ break;
+#endif /* !JS_BUG_FALLIBLE_EQOPS */
+
+#if JS_HAS_LEXICAL_CLOSURE
+ case JSOP_CLOSURE:
+ atom = GET_ATOM(cx, jp->script, pc);
+ JS_ASSERT(ATOM_IS_OBJECT(atom));
+ goto do_function;
+#endif /* JS_HAS_LEXICAL_CLOSURE */
+
+#if JS_HAS_EXPORT_IMPORT
+ case JSOP_EXPORTALL:
+ js_printf(jp, "\texport *\n");
+ todo = -2;
+ break;
+
+ case JSOP_EXPORTNAME:
+ atom = GET_ATOM(cx, jp->script, pc);
+ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
+ if (!rval)
+ return JS_FALSE;
+ RETRACT(&ss->sprinter, rval);
+ js_printf(jp, "\texport %s\n", rval);
+ todo = -2;
+ break;
+
+ case JSOP_IMPORTALL:
+ lval = POP_STR();
+ js_printf(jp, "\timport %s.*\n", lval);
+ todo = -2;
+ break;
+
+ case JSOP_IMPORTPROP:
+ GET_ATOM_QUOTE_AND_FMT("\timport %s[%s]\n", "\timport %s.%s\n",
+ rval);
+ lval = POP_STR();
+ js_printf(jp, fmt, lval, rval);
+ todo = -2;
+ break;
+
+ case JSOP_IMPORTELEM:
+ xval = POP_STR();
+ op = JSOP_GETELEM;
+ lval = POP_STR();
+ js_printf(jp, "\timport %s[%s]\n", lval, xval);
+ todo = -2;
+ break;
+#endif /* JS_HAS_EXPORT_IMPORT */
+
+ case JSOP_TRAP:
+ op = JS_GetTrapOpcode(cx, jp->script, pc);
+ if (op == JSOP_LIMIT)
+ return JS_FALSE;
+ *pc = op;
+ cs = &js_CodeSpec[op];
+ len = cs->length;
+ DECOMPILE_CODE(pc, len);
+ *pc = JSOP_TRAP;
+ todo = -2;
+ break;
+
+#if JS_HAS_INITIALIZERS
+ case JSOP_NEWINIT:
+ LOCAL_ASSERT(ss->top >= 2);
+ (void) PopOff(ss, op);
+ lval = POP_STR();
+#if JS_HAS_SHARP_VARS
+ op = (JSOp)pc[len];
+ if (op == JSOP_DEFSHARP) {
+ pc += len;
+ cs = &js_CodeSpec[op];
+ len = cs->length;
+ i = (jsint) GET_ATOM_INDEX(pc);
+ todo = Sprint(&ss->sprinter, "#%u=%c",
+ (unsigned) i,
+ (*lval == 'O') ? '{' : '[');
+ } else
+#endif /* JS_HAS_SHARP_VARS */
+ {
+ todo = Sprint(&ss->sprinter, (*lval == 'O') ? "{" : "[");
+ }
+ break;
+
+ case JSOP_ENDINIT:
+ rval = POP_STR();
+ sn = js_GetSrcNote(jp->script, pc);
+ todo = Sprint(&ss->sprinter, "%s%s%c",
+ rval,
+ (sn && SN_TYPE(sn) == SRC_CONTINUE) ? ", " : "",
+ (*rval == '{') ? '}' : ']');
+ break;
+
+ case JSOP_INITPROP:
+ case JSOP_INITCATCHVAR:
+ atom = GET_ATOM(cx, jp->script, pc);
+ xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
+ ATOM_KEYWORD(atom) ? '\'' : 0);
+ if (!xval)
+ return JS_FALSE;
+ rval = POP_STR();
+ lval = POP_STR();
+ do_initprop:
+#ifdef OLD_GETTER_SETTER
+ todo = Sprint(&ss->sprinter, "%s%s%s%s%s:%s",
+ lval,
+ (lval[1] != '\0') ? ", " : "",
+ xval,
+ (lastop == JSOP_GETTER || lastop == JSOP_SETTER)
+ ? " " : "",
+ (lastop == JSOP_GETTER) ? js_getter_str :
+ (lastop == JSOP_SETTER) ? js_setter_str :
+ "",
+ rval);
+#else
+ if (lastop == JSOP_GETTER || lastop == JSOP_SETTER) {
+ todo = Sprint(&ss->sprinter, "%s%s%s %s%s",
+ lval,
+ (lval[1] != '\0') ? ", " : "",
+ (lastop == JSOP_GETTER)
+ ? js_get_str : js_set_str,
+ xval,
+ rval + strlen(js_function_str) + 1);
+ } else {
+ todo = Sprint(&ss->sprinter, "%s%s%s:%s",
+ lval,
+ (lval[1] != '\0') ? ", " : "",
+ xval,
+ rval);
+ }
+#endif
+ break;
+
+ case JSOP_INITELEM:
+ rval = POP_STR();
+ xval = POP_STR();
+ lval = POP_STR();
+ sn = js_GetSrcNote(jp->script, pc);
+ if (sn && SN_TYPE(sn) == SRC_LABEL)
+ goto do_initprop;
+ todo = Sprint(&ss->sprinter, "%s%s%s",
+ lval,
+ (lval[1] != '\0' || *xval != '0') ? ", " : "",
+ rval);
+ break;
+
+#if JS_HAS_SHARP_VARS
+ case JSOP_DEFSHARP:
+ i = (jsint) GET_ATOM_INDEX(pc);
+ rval = POP_STR();
+ todo = Sprint(&ss->sprinter, "#%u=%s", (unsigned) i, rval);
+ break;
+
+ case JSOP_USESHARP:
+ i = (jsint) GET_ATOM_INDEX(pc);
+ todo = Sprint(&ss->sprinter, "#%u#", (unsigned) i);
+ break;
+#endif /* JS_HAS_SHARP_VARS */
+#endif /* JS_HAS_INITIALIZERS */
+
+#if JS_HAS_DEBUGGER_KEYWORD
+ case JSOP_DEBUGGER:
+ js_printf(jp, "\tdebugger;\n");
+ todo = -2;
+ break;
+#endif /* JS_HAS_DEBUGGER_KEYWORD */
+
+ default:
+ todo = -2;
+ break;
+ }
+ }
+
+ if (todo < 0) {
+ /* -2 means "don't push", -1 means reported error. */
+ if (todo == -1)
+ return JS_FALSE;
+ } else {
+ if (!PushOff(ss, todo, op))
+ return JS_FALSE;
+ }
+ pc += len;
+ }
+
+/*
+ * Undefine local macros.
+ */
+#undef DECOMPILE_CODE
+#undef POP_STR
+#undef LOCAL_ASSERT
+#undef GET_ATOM_QUOTE_AND_FMT
+
+ return JS_TRUE;
+}
+
+
+JSBool
+js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len)
+{
+ SprintStack ss;
+ JSContext *cx;
+ void *mark, *space;
+ size_t offsetsz, opcodesz;
+ JSBool ok;
+ JSScript *oldscript;
+ char *last;
+
+ /* Initialize a sprinter for use with the offset stack. */
+ ss.printer = jp;
+ cx = jp->sprinter.context;
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ INIT_SPRINTER(cx, &ss.sprinter, &cx->tempPool, PAREN_SLOP);
+
+ /* Allocate the parallel (to avoid padding) offset and opcode stacks. */
+ offsetsz = script->depth * sizeof(ptrdiff_t);
+ opcodesz = script->depth * sizeof(jsbytecode);
+ JS_ARENA_ALLOCATE(space, &cx->tempPool, offsetsz + opcodesz);
+ if (!space) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ ss.offsets = (ptrdiff_t *) space;
+ ss.opcodes = (jsbytecode *) ((char *)space + offsetsz);
+ ss.top = 0;
+
+ /* Call recursive subroutine to do the hard work. */
+ oldscript = jp->script;
+ jp->script = script;
+ ok = Decompile(&ss, pc, len);
+ jp->script = oldscript;
+
+ /* If the given code didn't empty the stack, do it now. */
+ if (ss.top) {
+ do {
+ last = OFF2STR(&ss.sprinter, PopOff(&ss, JSOP_NOP));
+ } while (ss.top);
+ js_printf(jp, "%s", last);
+ }
+
+out:
+ /* Free all temporary stuff allocated under this call. */
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return ok;
+}
+
+JSBool
+js_DecompileScript(JSPrinter *jp, JSScript *script)
+{
+ return js_DecompileCode(jp, script, script->code, (uintN)script->length);
+}
+
+static const char native_code_str[] = "\t[native code]\n";
+
+JSBool
+js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun)
+{
+ JSScript *script;
+ JSScope *scope, *save;
+ JSBool ok;
+
+ script = fun->script;
+ if (!script) {
+ js_printf(jp, native_code_str);
+ return JS_TRUE;
+ }
+ scope = fun->object ? OBJ_SCOPE(fun->object) : NULL;
+ save = jp->scope;
+ jp->scope = scope;
+ ok = js_DecompileCode(jp, script, script->code, (uintN)script->length);
+ jp->scope = save;
+ return ok;
+}
+
+JSBool
+js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
+{
+ JSContext *cx;
+ uintN i, nargs, indent;
+ void *mark;
+ JSAtom **params;
+ JSScope *scope, *oldscope;
+ JSScopeProperty *sprop;
+ JSBool ok;
+
+ /*
+ * If pretty, conform to ECMA-262 Edition 3, 15.3.4.2, by decompiling a
+ * FunctionDeclaration. Otherwise, check the JSFUN_LAMBDA flag and force
+ * an expression by parenthesizing.
+ */
+ if (jp->pretty) {
+ js_puts(jp, "\n");
+ js_printf(jp, "\t");
+ } else {
+ if (fun->flags & JSFUN_LAMBDA)
+ js_puts(jp, "(");
+ }
+ if (fun->flags & JSFUN_GETTER)
+ js_printf(jp, "%s ", js_getter_str);
+ else if (fun->flags & JSFUN_SETTER)
+ js_printf(jp, "%s ", js_setter_str);
+
+ js_printf(jp, "%s ", js_function_str);
+ if (fun->atom && !QuoteString(&jp->sprinter, ATOM_TO_STRING(fun->atom), 0))
+ return JS_FALSE;
+ js_puts(jp, "(");
+
+ if (fun->script && fun->object) {
+ /*
+ * Print the parameters.
+ *
+ * This code is complicated by the need to handle duplicate parameter
+ * names, as required by ECMA (bah!). A duplicate parameter is stored
+ * as another node with the same id (the parameter name) but different
+ * shortid (the argument index) along the property tree ancestor line
+ * starting at SCOPE_LAST_PROP(scope). Only the last duplicate param
+ * is mapped by the scope's hash table.
+ */
+ cx = jp->sprinter.context;
+ nargs = fun->nargs;
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ JS_ARENA_ALLOCATE_CAST(params, JSAtom **, &cx->tempPool,
+ nargs * sizeof(JSAtom *));
+ if (!params) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ scope = OBJ_SCOPE(fun->object);
+ for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
+ if (sprop->getter != js_GetArgument)
+ continue;
+ JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
+ JS_ASSERT((uintN) sprop->shortid < nargs);
+ JS_ASSERT(!JSVAL_IS_INT(sprop->id));
+ params[(uintN) sprop->shortid] = (JSAtom *) sprop->id;
+ }
+ for (i = 0; i < nargs; i++) {
+ if (i > 0)
+ js_puts(jp, ", ");
+ if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(params[i]), 0))
+ return JS_FALSE;
+ }
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+#ifdef __GNUC__
+ } else {
+ scope = NULL;
+#endif
+ }
+
+ js_printf(jp, ") {\n");
+ indent = jp->indent;
+ jp->indent += 4;
+ if (fun->script && fun->object) {
+ oldscope = jp->scope;
+ jp->scope = scope;
+ ok = js_DecompileScript(jp, fun->script);
+ jp->scope = oldscope;
+ if (!ok) {
+ jp->indent = indent;
+ return JS_FALSE;
+ }
+ } else {
+ js_printf(jp, native_code_str);
+ }
+ jp->indent -= 4;
+ js_printf(jp, "\t}");
+
+ if (jp->pretty) {
+ js_puts(jp, "\n");
+ } else {
+ if (fun->flags & JSFUN_LAMBDA)
+ js_puts(jp, ")");
+ }
+ return JS_TRUE;
+}
+
+JSString *
+js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
+ JSString *fallback)
+{
+ JSStackFrame *fp, *down;
+ jsbytecode *pc, *begin, *end, *tmp;
+ jsval *sp, *base, *limit;
+ JSScript *script;
+ JSOp op;
+ const JSCodeSpec *cs;
+ uint32 format, mode;
+ intN depth;
+ jssrcnote *sn;
+ uintN len, off;
+ JSPrinter *jp;
+ JSString *name;
+
+ fp = cx->fp;
+ if (!fp)
+ goto do_fallback;
+
+ /* Try to find sp's generating pc depth slots under it on the stack. */
+ pc = fp->pc;
+ if (spindex == JSDVG_SEARCH_STACK) {
+ if (!pc) {
+ /*
+ * Current frame is native: look under it for a scripted call
+ * in which a decompilable bytecode string that generated the
+ * value as an actual argument might exist.
+ */
+ JS_ASSERT(!fp->script && fp->fun && fp->fun->native);
+ down = fp->down;
+ if (!down)
+ goto do_fallback;
+ script = down->script;
+ base = fp->argv;
+ limit = base + fp->argc;
+ } else {
+ /*
+ * This should be a script activation, either a top-level
+ * script or a scripted function. But be paranoid about calls
+ * to js_DecompileValueGenerator from code that hasn't fully
+ * initialized a (default-all-zeroes) frame.
+ */
+ script = fp->script;
+ base = fp->spbase;
+ limit = fp->sp;
+ }
+
+ /*
+ * Pure paranoia about default-zeroed frames being active while
+ * js_DecompileValueGenerator is called. It can't hurt much now;
+ * error reporting performance is not an issue.
+ */
+ if (!script || !base || !limit)
+ goto do_fallback;
+
+ /*
+ * Try to find operand-generating pc depth slots below sp.
+ *
+ * In the native case, we know the arguments have generating pc's
+ * under them, on account of fp->down->script being non-null: all
+ * compiled scripts get depth slots for generating pc's allocated
+ * upon activation, at the top of js_Interpret.
+ *
+ * In the script or scripted function case, the same reasoning
+ * applies to fp rather than to fp->down.
+ */
+ for (sp = base; sp < limit; sp++) {
+ if (*sp == v) {
+ depth = (intN)script->depth;
+ pc = (jsbytecode *) sp[-depth];
+ break;
+ }
+ }
+ } else {
+ /*
+ * At this point, pc may or may not be null, i.e., we could be in
+ * a script activation, or we could be in a native frame that was
+ * called by another native function. Check pc and script.
+ */
+ if (!pc)
+ goto do_fallback;
+ script = fp->script;
+ if (!script)
+ goto do_fallback;
+
+ if (spindex != JSDVG_IGNORE_STACK) {
+ JS_ASSERT(spindex < 0);
+ depth = (intN)script->depth;
+#if !JS_HAS_NO_SUCH_METHOD
+ JS_ASSERT(-depth <= spindex);
+#endif
+ spindex -= depth;
+
+ base = (jsval *) cx->stackPool.current->base;
+ limit = (jsval *) cx->stackPool.current->avail;
+ sp = fp->sp + spindex;
+ if (JS_UPTRDIFF(sp, base) < JS_UPTRDIFF(limit, base))
+ pc = (jsbytecode *) *sp;
+ }
+ }
+
+ /*
+ * Again, be paranoid, this time about possibly loading an invalid pc
+ * from sp[-(1+depth)].
+ */
+ if (JS_UPTRDIFF(pc, script->code) >= (jsuword)script->length) {
+ pc = fp->pc;
+ if (!pc)
+ goto do_fallback;
+ }
+ op = (JSOp) *pc;
+ if (op == JSOP_TRAP)
+ op = JS_GetTrapOpcode(cx, script, pc);
+
+ /* XXX handle null as a special case, to avoid calling null "object" */
+ if (op == JSOP_NULL)
+ return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
+
+ cs = &js_CodeSpec[op];
+ format = cs->format;
+ mode = (format & JOF_MODEMASK);
+
+ /* NAME ops are self-contained, but others require left context. */
+ if (mode == JOF_NAME) {
+ begin = pc;
+ } else {
+ sn = js_GetSrcNote(script, pc);
+ if (!sn || SN_TYPE(sn) != SRC_PCBASE)
+ goto do_fallback;
+ begin = pc - js_GetSrcNoteOffset(sn, 0);
+ }
+ end = pc + cs->length;
+ len = PTRDIFF(end, begin, jsbytecode);
+
+ if (format & (JOF_SET | JOF_DEL | JOF_INCDEC | JOF_IMPORT | JOF_FOR)) {
+ tmp = (jsbytecode *) JS_malloc(cx, len * sizeof(jsbytecode));
+ if (!tmp)
+ return NULL;
+ memcpy(tmp, begin, len * sizeof(jsbytecode));
+ if (mode == JOF_NAME) {
+ tmp[0] = JSOP_NAME;
+ } else {
+ /*
+ * We must replace the faulting pc's bytecode with a corresponding
+ * JSOP_GET* code. For JSOP_SET{PROP,ELEM}, we must use the "2nd"
+ * form of JSOP_GET{PROP,ELEM}, to throw away the assignment op's
+ * right-hand operand and decompile it as if it were a GET of its
+ * left-hand operand.
+ */
+ off = len - cs->length;
+ JS_ASSERT(off == (uintN) PTRDIFF(pc, begin, jsbytecode));
+ if (mode == JOF_PROP) {
+ tmp[off] = (format & JOF_SET) ? JSOP_GETPROP2 : JSOP_GETPROP;
+ } else if (mode == JOF_ELEM) {
+ tmp[off] = (format & JOF_SET) ? JSOP_GETELEM2 : JSOP_GETELEM;
+ } else {
+ /*
+ * A zero mode means precisely that op is uncategorized for our
+ * purposes, so we must write per-op special case code here.
+ */
+ switch (op) {
+ case JSOP_ENUMELEM:
+ tmp[off] = JSOP_GETELEM;
+ break;
+#if JS_HAS_LVALUE_RETURN
+ case JSOP_SETCALL:
+ tmp[off] = JSOP_CALL;
+ break;
+#endif
+ default:
+ JS_ASSERT(0);
+ }
+ }
+ }
+ begin = tmp;
+ } else {
+ /* No need to revise script bytecode. */
+ tmp = NULL;
+ }
+
+ jp = js_NewPrinter(cx, "js_DecompileValueGenerator", 0, JS_FALSE);
+ if (jp && js_DecompileCode(jp, script, begin, len))
+ name = js_GetPrinterOutput(jp);
+ else
+ name = NULL;
+ js_DestroyPrinter(jp);
+ if (tmp)
+ JS_free(cx, tmp);
+ return name;
+
+ do_fallback:
+ return fallback ? fallback : js_ValueToString(cx, v);
+}
diff --git a/src/dom/js/jsopcode.h b/src/dom/js/jsopcode.h
new file mode 100644
index 000000000..e24fb2bf8
--- /dev/null
+++ b/src/dom/js/jsopcode.h
@@ -0,0 +1,273 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsopcode_h___
+#define jsopcode_h___
+/*
+ * JS bytecode definitions.
+ */
+#include <stddef.h>
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * JS operation bytecodes.
+ */
+typedef enum JSOp {
+#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
+ op = val,
+#include "jsopcode.tbl"
+#undef OPDEF
+ JSOP_LIMIT
+} JSOp;
+
+/*
+ * JS bytecode formats.
+ */
+#define JOF_BYTE 0 /* single bytecode, no immediates */
+#define JOF_JUMP 1 /* signed 16-bit jump offset immediate */
+#define JOF_CONST 2 /* unsigned 16-bit constant pool index */
+#define JOF_UINT16 3 /* unsigned 16-bit immediate operand */
+#define JOF_TABLESWITCH 4 /* table switch */
+#define JOF_LOOKUPSWITCH 5 /* lookup switch */
+#define JOF_QARG 6 /* quickened get/set function argument ops */
+#define JOF_QVAR 7 /* quickened get/set local variable ops */
+#define JOF_DEFLOCALVAR 8 /* define local var with initial value */
+#define JOF_JUMPX 9 /* signed 32-bit jump offset immediate */
+#define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */
+#define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */
+#define JOF_TYPEMASK 0x000f /* mask for above immediate types */
+#define JOF_NAME 0x0010 /* name operation */
+#define JOF_PROP 0x0020 /* obj.prop operation */
+#define JOF_ELEM 0x0030 /* obj[index] operation */
+#define JOF_MODEMASK 0x0030 /* mask for above addressing modes */
+#define JOF_SET 0x0040 /* set (i.e., assignment) operation */
+#define JOF_DEL 0x0080 /* delete operation */
+#define JOF_DEC 0x0100 /* decrement (--, not ++) opcode */
+#define JOF_INC 0x0200 /* increment (++, not --) opcode */
+#define JOF_INCDEC 0x0300 /* increment or decrement opcode */
+#define JOF_POST 0x0400 /* postorder increment or decrement */
+#define JOF_IMPORT 0x0800 /* import property op */
+#define JOF_FOR 0x1000 /* for-in property op */
+#define JOF_ASSIGNING JOF_SET /* hint for JSClass.resolve, used for ops
+ that do simplex assignment */
+#define JOF_BACKPATCH 0x4000 /* backpatch placeholder during codegen */
+#define JOF_LEFTASSOC 0x8000 /* left-associative operator */
+
+#define JOF_TYPE_IS_EXTENDED_JUMP(t) \
+ ((unsigned)((t) - JOF_JUMPX) <= (unsigned)(JOF_LOOKUPSWITCHX - JOF_JUMPX))
+
+/*
+ * Immediate operand getters, setters, and bounds.
+ */
+
+/* Short (2-byte signed offset) relative jump macros. */
+#define JUMP_OFFSET_LEN 2
+#define JUMP_OFFSET_HI(off) ((jsbytecode)((off) >> 8))
+#define JUMP_OFFSET_LO(off) ((jsbytecode)(off))
+#define GET_JUMP_OFFSET(pc) ((int16)(((pc)[1] << 8) | (pc)[2]))
+#define SET_JUMP_OFFSET(pc,off) ((pc)[1] = JUMP_OFFSET_HI(off), \
+ (pc)[2] = JUMP_OFFSET_LO(off))
+#define JUMP_OFFSET_MIN ((int16)0x8000)
+#define JUMP_OFFSET_MAX ((int16)0x7fff)
+
+/*
+ * When a short jump won't hold a relative offset, its 2-byte immediate offset
+ * operand is an unsigned index of a span-dependency record, maintained until
+ * code generation finishes -- after which some (but we hope not nearly all)
+ * span-dependent jumps must be extended (see OptimizeSpanDeps in jsemit.c).
+ *
+ * If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump
+ * offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be
+ * found (via binary search) by its "before span-dependency optimization" pc
+ * offset (from script main entry point).
+ */
+#define GET_SPANDEP_INDEX(pc) ((uint16)(((pc)[1] << 8) | (pc)[2]))
+#define SET_SPANDEP_INDEX(pc,i) ((pc)[1] = JUMP_OFFSET_HI(i), \
+ (pc)[2] = JUMP_OFFSET_LO(i))
+#define SPANDEP_INDEX_MAX ((uint16)0xfffe)
+#define SPANDEP_INDEX_HUGE ((uint16)0xffff)
+
+/* Ultimately, if short jumps won't do, emit long (4-byte signed) offsets. */
+#define JUMPX_OFFSET_LEN 4
+#define JUMPX_OFFSET_B3(off) ((jsbytecode)((off) >> 24))
+#define JUMPX_OFFSET_B2(off) ((jsbytecode)((off) >> 16))
+#define JUMPX_OFFSET_B1(off) ((jsbytecode)((off) >> 8))
+#define JUMPX_OFFSET_B0(off) ((jsbytecode)(off))
+#define GET_JUMPX_OFFSET(pc) ((int32)(((pc)[1] << 24) | ((pc)[2] << 16) \
+ | ((pc)[3] << 8) | (pc)[4]))
+#define SET_JUMPX_OFFSET(pc,off)((pc)[1] = JUMPX_OFFSET_B3(off), \
+ (pc)[2] = JUMPX_OFFSET_B2(off), \
+ (pc)[3] = JUMPX_OFFSET_B1(off), \
+ (pc)[4] = JUMPX_OFFSET_B0(off))
+#define JUMPX_OFFSET_MIN ((int32)0x80000000)
+#define JUMPX_OFFSET_MAX ((int32)0x7fffffff)
+
+/* A literal is indexed by a per-script atom map. */
+#define ATOM_INDEX_LEN 2
+#define ATOM_INDEX_HI(index) ((jsbytecode)((index) >> 8))
+#define ATOM_INDEX_LO(index) ((jsbytecode)(index))
+#define GET_ATOM_INDEX(pc) ((jsatomid)(((pc)[1] << 8) | (pc)[2]))
+#define SET_ATOM_INDEX(pc,index)((pc)[1] = ATOM_INDEX_HI(index), \
+ (pc)[2] = ATOM_INDEX_LO(index))
+#define GET_ATOM(cx,script,pc) js_GetAtom((cx), &(script)->atomMap, \
+ GET_ATOM_INDEX(pc))
+#define ATOM_INDEX_LIMIT_LOG2 16
+#define ATOM_INDEX_LIMIT ((uint32)1 << ATOM_INDEX_LIMIT_LOG2)
+
+/* Actual argument count operand format helpers. */
+#define ARGC_HI(argc) ((jsbytecode)((argc) >> 8))
+#define ARGC_LO(argc) ((jsbytecode)(argc))
+#define GET_ARGC(pc) ((uintN)(((pc)[1] << 8) | (pc)[2]))
+#define ARGC_LIMIT ((uint32)1 << 16)
+
+/* Synonyms for quick JOF_QARG and JOF_QVAR bytecodes. */
+#define GET_ARGNO(pc) GET_ARGC(pc)
+#define SET_ARGNO(pc,argno) SET_JUMP_OFFSET(pc,argno)
+#define ARGNO_LEN JUMP_OFFSET_LEN
+#define GET_VARNO(pc) GET_ARGC(pc)
+#define SET_VARNO(pc,varno) SET_JUMP_OFFSET(pc,varno)
+#define VARNO_LEN JUMP_OFFSET_LEN
+
+struct JSCodeSpec {
+ const char *name; /* JS bytecode name */
+ const char *token; /* JS source literal or null */
+ int8 length; /* length including opcode byte */
+ int8 nuses; /* arity, -1 if variadic */
+ int8 ndefs; /* number of stack results */
+ uint8 prec; /* operator precedence */
+ uint32 format; /* immediate operand format */
+};
+
+extern const char js_const_str[];
+extern const char js_var_str[];
+extern const char js_function_str[];
+extern const char js_in_str[];
+extern const char js_instanceof_str[];
+extern const char js_new_str[];
+extern const char js_delete_str[];
+extern const char js_typeof_str[];
+extern const char js_void_str[];
+extern const char js_null_str[];
+extern const char js_this_str[];
+extern const char js_false_str[];
+extern const char js_true_str[];
+extern const JSCodeSpec js_CodeSpec[];
+extern uintN js_NumCodeSpecs;
+extern const jschar js_EscapeMap[];
+
+/*
+ * Return a GC'ed string containing the chars in str, with any non-printing
+ * chars or quotes (' or " as specified by the quote argument) escaped, and
+ * with the quote character at the beginning and end of the result string.
+ */
+extern JSString *
+js_QuoteString(JSContext *cx, JSString *str, jschar quote);
+
+/*
+ * JSPrinter operations, for printf style message formatting. The return
+ * value from js_GetPrinterOutput() is the printer's cumulative output, in
+ * a GC'ed string.
+ */
+extern JSPrinter *
+js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty);
+
+extern void
+js_DestroyPrinter(JSPrinter *jp);
+
+extern JSString *
+js_GetPrinterOutput(JSPrinter *jp);
+
+extern int
+js_printf(JSPrinter *jp, const char *format, ...);
+
+extern JSBool
+js_puts(JSPrinter *jp, const char *s);
+
+#ifdef DEBUG
+/*
+ * Disassemblers, for debugging only.
+ */
+#include <stdio.h>
+
+extern JS_FRIEND_API(void)
+js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp);
+
+extern JS_FRIEND_API(uintN)
+js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
+ JSBool lines, FILE *fp);
+#endif /* DEBUG */
+
+/*
+ * Decompilers, for script, function, and expression pretty-printing.
+ */
+extern JSBool
+js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len);
+
+extern JSBool
+js_DecompileScript(JSPrinter *jp, JSScript *script);
+
+extern JSBool
+js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun);
+
+extern JSBool
+js_DecompileFunction(JSPrinter *jp, JSFunction *fun);
+
+/*
+ * Find the source expression that resulted in v, and return a new string
+ * containing it. Fall back on v's string conversion (fallback) if we can't
+ * find the bytecode that generated and pushed v on the operand stack.
+ *
+ * Search the current stack frame if spindex is JSDVG_SEARCH_STACK. Don't
+ * look for v on the stack if spindex is JSDVG_IGNORE_STACK. Otherwise,
+ * spindex is the negative index of v, measured from cx->fp->sp, or from a
+ * lower frame's sp if cx->fp is native.
+ */
+extern JSString *
+js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
+ JSString *fallback);
+
+#define JSDVG_IGNORE_STACK 0
+#define JSDVG_SEARCH_STACK 1
+
+JS_END_EXTERN_C
+
+#endif /* jsopcode_h___ */
diff --git a/src/dom/js/jsopcode.tbl b/src/dom/js/jsopcode.tbl
new file mode 100644
index 000000000..d4bad0fd9
--- /dev/null
+++ b/src/dom/js/jsopcode.tbl
@@ -0,0 +1,333 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JavaScript operation bytecodes. If you need to allocate a bytecode, look
+ * for a name of the form JSOP_UNUSED* and claim it. Otherwise, always add at
+ * the end of the table.
+ *
+ * Includers must define an OPDEF macro of the following form:
+ *
+ * #define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) ...
+ *
+ * Selected arguments can be expanded in initializers. The op argument is
+ * expanded followed by comma in the JSOp enum (jsopcode.h), e.g. The value
+ * field must be dense for now, because jsopcode.c uses an OPDEF() expansion
+ * inside the js_CodeSpec[] initializer.
+ *
+ * Field Description
+ * op Bytecode name, which is the JSOp enumerator name
+ * value Bytecode value, which is the JSOp enumerator value
+ * name C string containing name for disassembler
+ * image C string containing "image" for pretty-printer, null if ugly
+ * length Number of bytes including any immediate operands
+ * nuses Number of stack slots consumed by bytecode, -1 if variadic
+ * ndefs Number of stack slots produced by bytecode
+ * prec Operator precedence, zero if not an operator
+ * format Bytecode plus immediate operand encoding format
+ *
+ * This file is best viewed with 116 columns:
+01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345
+ */
+
+/* legend: op val name image len use def prec format */
+
+/* Longstanding JavaScript bytecodes. */
+OPDEF(JSOP_NOP, 0, "nop", NULL, 1, 0, 0, 0, JOF_BYTE)
+OPDEF(JSOP_PUSH, 1, "push", NULL, 1, 0, 1, 0, JOF_BYTE)
+OPDEF(JSOP_POPV, 2, "popv", NULL, 1, 1, 0, 0, JOF_BYTE)
+OPDEF(JSOP_ENTERWITH, 3, "enterwith", NULL, 1, 1, 1, 0, JOF_BYTE)
+OPDEF(JSOP_LEAVEWITH, 4, "leavewith", NULL, 1, 1, 0, 0, JOF_BYTE)
+OPDEF(JSOP_RETURN, 5, "return", NULL, 1, 1, 0, 0, JOF_BYTE)
+OPDEF(JSOP_GOTO, 6, "goto", NULL, 3, 0, 0, 0, JOF_JUMP)
+OPDEF(JSOP_IFEQ, 7, "ifeq", NULL, 3, 1, 0, 0, JOF_JUMP)
+OPDEF(JSOP_IFNE, 8, "ifne", NULL, 3, 1, 0, 0, JOF_JUMP)
+
+/* Get the arguments object for the current, lightweight function activation. */
+OPDEF(JSOP_ARGUMENTS, 9, js_arguments_str, js_arguments_str, 1, 0, 1, 12, JOF_BYTE)
+
+/* ECMA-compliant for-in loop with argument or local variable loop control. */
+OPDEF(JSOP_FORARG, 10, "forarg", NULL, 3, 0, 1, 0, JOF_QARG|JOF_NAME|JOF_FOR)
+OPDEF(JSOP_FORVAR, 11, "forvar", NULL, 3, 0, 1, 0, JOF_QVAR|JOF_NAME|JOF_FOR)
+
+/* More longstanding bytecodes. */
+OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE)
+OPDEF(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, 0, JOF_BYTE)
+OPDEF(JSOP_SETCONST, 14, "setconst", NULL, 3, 1, 1, 1, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING)
+OPDEF(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, 2, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, 3, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, 4, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_EQ, 18, "eq", "==", 1, 2, 1, 5, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_NE, 19, "ne", "!=", 1, 2, 1, 5, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_LT, 20, "lt", "<", 1, 2, 1, 6, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_LE, 21, "le", "<=", 1, 2, 1, 6, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_GT, 22, "gt", ">", 1, 2, 1, 6, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_GE, 23, "ge", ">=", 1, 2, 1, 6, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_ADD, 27, "add", "+", 1, 2, 1, 8, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_SUB, 28, "sub", "-", 1, 2, 1, 8, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_MUL, 29, "mul", "*", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_DIV, 30, "div", "/", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_MOD, 31, "mod", "%", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_NOT, 32, "not", "!", 1, 1, 1, 10, JOF_BYTE)
+OPDEF(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, 10, JOF_BYTE)
+OPDEF(JSOP_NEG, 34, "neg", "-", 1, 1, 1, 10, JOF_BYTE)
+OPDEF(JSOP_NEW, 35, js_new_str, NULL, 3, -1, 1, 10, JOF_UINT16)
+OPDEF(JSOP_DELNAME, 36, "delname", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_DEL)
+OPDEF(JSOP_DELPROP, 37, "delprop", NULL, 3, 1, 1, 10, JOF_CONST|JOF_PROP|JOF_DEL)
+OPDEF(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_DEL)
+OPDEF(JSOP_TYPEOF, 39, js_typeof_str,NULL, 1, 1, 1, 10, JOF_BYTE)
+OPDEF(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, 10, JOF_BYTE)
+OPDEF(JSOP_INCNAME, 41, "incname", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_INC)
+OPDEF(JSOP_INCPROP, 42, "incprop", NULL, 3, 1, 1, 10, JOF_CONST|JOF_PROP|JOF_INC)
+OPDEF(JSOP_INCELEM, 43, "incelem", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_INC)
+OPDEF(JSOP_DECNAME, 44, "decname", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_DEC)
+OPDEF(JSOP_DECPROP, 45, "decprop", NULL, 3, 1, 1, 10, JOF_CONST|JOF_PROP|JOF_DEC)
+OPDEF(JSOP_DECELEM, 46, "decelem", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_DEC)
+OPDEF(JSOP_NAMEINC, 47, "nameinc", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_INC|JOF_POST)
+OPDEF(JSOP_PROPINC, 48, "propinc", NULL, 3, 1, 1, 10, JOF_CONST|JOF_PROP|JOF_INC|JOF_POST)
+OPDEF(JSOP_ELEMINC, 49, "eleminc", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_INC|JOF_POST)
+OPDEF(JSOP_NAMEDEC, 50, "namedec", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_DEC|JOF_POST)
+OPDEF(JSOP_PROPDEC, 51, "propdec", NULL, 3, 1, 1, 10, JOF_CONST|JOF_PROP|JOF_DEC|JOF_POST)
+OPDEF(JSOP_ELEMDEC, 52, "elemdec", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_POST)
+OPDEF(JSOP_GETPROP, 53, "getprop", NULL, 3, 1, 1, 11, JOF_CONST|JOF_PROP)
+OPDEF(JSOP_SETPROP, 54, "setprop", NULL, 3, 2, 1, 1, JOF_CONST|JOF_PROP|JOF_SET|JOF_ASSIGNING)
+OPDEF(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, 11, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC)
+OPDEF(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, 1, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_ASSIGNING)
+OPDEF(JSOP_PUSHOBJ, 57, "pushobj", NULL, 1, 0, 1, 0, JOF_BYTE)
+OPDEF(JSOP_CALL, 58, "call", NULL, 3, -1, 1, 11, JOF_UINT16)
+OPDEF(JSOP_NAME, 59, "name", NULL, 3, 0, 1, 12, JOF_CONST|JOF_NAME)
+OPDEF(JSOP_NUMBER, 60, "number", NULL, 3, 0, 1, 12, JOF_CONST)
+OPDEF(JSOP_STRING, 61, "string", NULL, 3, 0, 1, 12, JOF_CONST)
+OPDEF(JSOP_ZERO, 62, "zero", "0", 1, 0, 1, 12, JOF_BYTE)
+OPDEF(JSOP_ONE, 63, "one", "1", 1, 0, 1, 12, JOF_BYTE)
+OPDEF(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, 12, JOF_BYTE)
+OPDEF(JSOP_THIS, 65, js_this_str, js_this_str, 1, 0, 1, 12, JOF_BYTE)
+OPDEF(JSOP_FALSE, 66, js_false_str, js_false_str, 1, 0, 1, 12, JOF_BYTE)
+OPDEF(JSOP_TRUE, 67, js_true_str, js_true_str, 1, 0, 1, 12, JOF_BYTE)
+OPDEF(JSOP_OR, 68, "or", NULL, 3, 1, 0, 0, JOF_JUMP)
+OPDEF(JSOP_AND, 69, "and", NULL, 3, 1, 0, 0, JOF_JUMP)
+
+/* The switch bytecodes have variable length. */
+OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH)
+OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCH)
+
+/* New, infallible/transitive identity ops. */
+OPDEF(JSOP_NEW_EQ, 72, "eq", NULL, 1, 2, 1, 5, JOF_BYTE)
+OPDEF(JSOP_NEW_NE, 73, "ne", NULL, 1, 2, 1, 5, JOF_BYTE)
+
+/* Lexical closure constructor. */
+OPDEF(JSOP_CLOSURE, 74, "closure", NULL, 3, 0, 0, 0, JOF_CONST)
+
+/* Export and import ops. */
+OPDEF(JSOP_EXPORTALL, 75, "exportall", NULL, 1, 0, 0, 0, JOF_BYTE)
+OPDEF(JSOP_EXPORTNAME,76, "exportname", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME)
+OPDEF(JSOP_IMPORTALL, 77, "importall", NULL, 1, 1, 0, 0, JOF_BYTE)
+OPDEF(JSOP_IMPORTPROP,78, "importprop", NULL, 3, 1, 0, 0, JOF_CONST|JOF_PROP|JOF_IMPORT)
+OPDEF(JSOP_IMPORTELEM,79, "importelem", NULL, 1, 2, 0, 0, JOF_BYTE |JOF_ELEM|JOF_IMPORT)
+
+/* Push object literal. */
+OPDEF(JSOP_OBJECT, 80, "object", NULL, 3, 0, 1, 12, JOF_CONST)
+
+/* Pop value and discard it. */
+OPDEF(JSOP_POP, 81, "pop", NULL, 1, 1, 0, 0, JOF_BYTE)
+
+/* Convert value to number, for unary +. */
+OPDEF(JSOP_POS, 82, "pos", "+", 1, 1, 1, 10, JOF_BYTE)
+
+/* Trap into debugger for breakpoint, etc. */
+OPDEF(JSOP_TRAP, 83, "trap", NULL, 1, 0, 0, 0, JOF_BYTE)
+
+/* Fast get/set ops for function arguments and local variables. */
+OPDEF(JSOP_GETARG, 84, "getarg", NULL, 3, 0, 1, 12, JOF_QARG |JOF_NAME)
+OPDEF(JSOP_SETARG, 85, "setarg", NULL, 3, 1, 1, 1, JOF_QARG |JOF_NAME|JOF_SET|JOF_ASSIGNING)
+OPDEF(JSOP_GETVAR, 86, "getvar", NULL, 3, 0, 1, 12, JOF_QVAR |JOF_NAME)
+OPDEF(JSOP_SETVAR, 87, "setvar", NULL, 3, 1, 1, 1, JOF_QVAR |JOF_NAME|JOF_SET|JOF_ASSIGNING)
+
+/* Push unsigned 16-bit int constant. */
+OPDEF(JSOP_UINT16, 88, "uint16", NULL, 3, 0, 1, 12, JOF_UINT16)
+
+/* Object and array literal support. */
+OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 1, 2, 1, 10, JOF_BYTE)
+OPDEF(JSOP_ENDINIT, 90, "endinit", NULL, 1, 0, 0, 0, JOF_BYTE)
+OPDEF(JSOP_INITPROP, 91, "initprop", NULL, 3, 1, 0, 0, JOF_CONST|JOF_PROP)
+OPDEF(JSOP_INITELEM, 92, "initelem", NULL, 1, 2, 0, 0, JOF_BYTE |JOF_ELEM)
+OPDEF(JSOP_DEFSHARP, 93, "defsharp", NULL, 3, 0, 0, 0, JOF_UINT16)
+OPDEF(JSOP_USESHARP, 94, "usesharp", NULL, 3, 0, 1, 0, JOF_UINT16)
+
+/* Fast inc/dec ops for args and local vars. */
+OPDEF(JSOP_INCARG, 95, "incarg", NULL, 3, 0, 1, 10, JOF_QARG |JOF_NAME|JOF_INC)
+OPDEF(JSOP_INCVAR, 96, "incvar", NULL, 3, 0, 1, 10, JOF_QVAR |JOF_NAME|JOF_INC)
+OPDEF(JSOP_DECARG, 97, "decarg", NULL, 3, 0, 1, 10, JOF_QARG |JOF_NAME|JOF_DEC)
+OPDEF(JSOP_DECVAR, 98, "decvar", NULL, 3, 0, 1, 10, JOF_QVAR |JOF_NAME|JOF_DEC)
+OPDEF(JSOP_ARGINC, 99, "arginc", NULL, 3, 0, 1, 10, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST)
+OPDEF(JSOP_VARINC, 100,"varinc", NULL, 3, 0, 1, 10, JOF_QVAR |JOF_NAME|JOF_INC|JOF_POST)
+OPDEF(JSOP_ARGDEC, 101,"argdec", NULL, 3, 0, 1, 10, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST)
+OPDEF(JSOP_VARDEC, 102,"vardec", NULL, 3, 0, 1, 10, JOF_QVAR |JOF_NAME|JOF_DEC|JOF_POST)
+
+/* ECMA-compliant for/in ops. */
+OPDEF(JSOP_TOOBJECT, 103,"toobject", NULL, 1, 1, 1, 0, JOF_BYTE)
+OPDEF(JSOP_FORNAME, 104,"forname", NULL, 3, 0, 1, 0, JOF_CONST|JOF_NAME|JOF_FOR)
+OPDEF(JSOP_FORPROP, 105,"forprop", NULL, 3, 1, 1, 0, JOF_CONST|JOF_PROP|JOF_FOR)
+OPDEF(JSOP_FORELEM, 106,"forelem", NULL, 1, 2, 4, 0, JOF_BYTE |JOF_ELEM|JOF_FOR)
+OPDEF(JSOP_POP2, 107,"pop2", NULL, 1, 2, 0, 0, JOF_BYTE)
+
+/* ECMA-compliant assignment ops. */
+OPDEF(JSOP_BINDNAME, 108,"bindname", NULL, 3, 0, 1, 0, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING)
+OPDEF(JSOP_SETNAME, 109,"setname", NULL, 3, 2, 1, 1, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING)
+
+/* Exception handling ops. */
+OPDEF(JSOP_THROW, 110,"throw", NULL, 1, 1, 0, 0, JOF_BYTE)
+
+/* 'in' and 'instanceof' ops. */
+OPDEF(JSOP_IN, 111,js_in_str, js_in_str, 1, 2, 1, 6, JOF_BYTE|JOF_LEFTASSOC)
+OPDEF(JSOP_INSTANCEOF,112,js_instanceof_str,js_instanceof_str,1,2,1,6,JOF_BYTE|JOF_LEFTASSOC)
+
+/* debugger op */
+OPDEF(JSOP_DEBUGGER, 113,"debugger", NULL, 1, 0, 0, 0, JOF_BYTE)
+
+/* gosub/retsub for finally handling */
+OPDEF(JSOP_GOSUB, 114,"gosub", NULL, 3, 0, 1, 0, JOF_JUMP)
+OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 1, 0, 0, JOF_BYTE)
+
+/* More exception handling ops. */
+OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE)
+OPDEF(JSOP_SETSP, 117,"setsp", NULL, 3, 0, 0, 0, JOF_UINT16)
+
+/*
+ * ECMA-compliant switch statement ops.
+ * CONDSWITCH is a decompilable NOP; CASE is ===, POP, jump if true, re-push
+ * lval if false; and DEFAULT is POP lval and GOTO.
+ */
+OPDEF(JSOP_CONDSWITCH,118,"condswitch", NULL, 1, 0, 0, 0, JOF_BYTE)
+OPDEF(JSOP_CASE, 119,"case", NULL, 3, 1, 0, 0, JOF_JUMP)
+OPDEF(JSOP_DEFAULT, 120,"default", NULL, 3, 1, 0, 0, JOF_JUMP)
+
+/*
+ * ECMA-compliant call to eval op
+ */
+OPDEF(JSOP_EVAL, 121,"eval", NULL, 3, -1, 1, 11, JOF_UINT16)
+
+/*
+ * ECMA-compliant helper for 'for (x[i] in o)' loops.
+ */
+OPDEF(JSOP_ENUMELEM, 122,"enumelem", NULL, 1, 3, 0, 1, JOF_BYTE |JOF_SET|JOF_ASSIGNING)
+
+/*
+ * Getter and setter prefix bytecodes. These modify the next bytecode, either
+ * an assignment or a property initializer code, which then defines a property
+ * getter or setter.
+ */
+OPDEF(JSOP_GETTER, 123,js_getter_str,js_getter_str,1, 0, 0, 0, JOF_BYTE)
+OPDEF(JSOP_SETTER, 124,js_setter_str,js_setter_str,1, 0, 0, 0, JOF_BYTE)
+
+/*
+ * Prolog bytecodes for defining function, var, and const names.
+ */
+OPDEF(JSOP_DEFFUN, 125,"deffun", NULL, 3, 0, 0, 0, JOF_CONST)
+OPDEF(JSOP_DEFCONST, 126,"defconst", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME)
+OPDEF(JSOP_DEFVAR, 127,"defvar", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME)
+
+/* Auto-clone (if needed due to re-parenting) and push an anonymous function. */
+OPDEF(JSOP_ANONFUNOBJ, 128, "anonfunobj", NULL, 3, 0, 1, 12, JOF_CONST)
+
+/* ECMA ed. 3 named function expression. */
+OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 12, JOF_CONST)
+
+/* Like JSOP_INITPROP, but specialized to make a DontDelete property for ECMA ed. 3 catch variables. */
+OPDEF(JSOP_INITCATCHVAR,130, "initcatchvar",NULL, 3, 1, 0, 0, JOF_CONST|JOF_PROP)
+
+/* ECMA-mandated parenthesization opcode, which nulls the reference base register, obj; see jsinterp.c. */
+OPDEF(JSOP_GROUP, 131, "group", NULL, 1, 0, 0, 0, JOF_BYTE)
+
+/* Host object extension: given 'o.item(i) = j', the left-hand side compiles JSOP_SETCALL, rather than JSOP_CALL. */
+OPDEF(JSOP_SETCALL, 132, "setcall", NULL, 3, -1, 2, 11, JOF_UINT16|JOF_SET|JOF_ASSIGNING)
+
+/*
+ * Exception handling no-ops, for more economical byte-coding than SRC_TRYFIN
+ * srcnote-annotated JSOP_NOPs.
+ */
+OPDEF(JSOP_TRY, 133,"try", NULL, 1, 0, 0, 0, JOF_BYTE)
+OPDEF(JSOP_FINALLY, 134,"finally", NULL, 1, 0, 0, 0, JOF_BYTE)
+
+/*
+ * Swap the top two stack elements.
+ * N.B. JSOP_SWAP doesn't swap the corresponding pc stack generating pcs, as
+ * they're not needed for the current use of preserving the top-of-stack return
+ * value when popping scopes while returning from catch blocks.
+ */
+OPDEF(JSOP_SWAP, 135,"swap", NULL, 1, 2, 2, 0, JOF_BYTE)
+
+/*
+ * Bytecodes that avoid making an arguments object in most cases:
+ * JSOP_ARGSUB gets arguments[i] from fp->argv, iff i is in [0, fp->argc-1].
+ * JSOP_ARGCNT returns fp->argc.
+ */
+OPDEF(JSOP_ARGSUB, 136,"argsub", NULL, 3, 0, 1, 12, JOF_QARG |JOF_NAME)
+OPDEF(JSOP_ARGCNT, 137,"argcnt", NULL, 1, 0, 1, 12, JOF_BYTE)
+
+/*
+ * Define a local function object as a local variable.
+ * The local variable's slot number is the first immediate two-byte operand.
+ * The function object's atom index is the second immediate operand.
+ */
+OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL, 5, 0, 0, 0, JOF_DEFLOCALVAR)
+
+/* Extended jumps. */
+OPDEF(JSOP_GOTOX, 139,"gotox", NULL, 5, 0, 0, 0, JOF_JUMPX)
+OPDEF(JSOP_IFEQX, 140,"ifeqx", NULL, 5, 1, 0, 0, JOF_JUMPX)
+OPDEF(JSOP_IFNEX, 141,"ifnex", NULL, 5, 1, 0, 0, JOF_JUMPX)
+OPDEF(JSOP_ORX, 142,"orx", NULL, 5, 1, 0, 0, JOF_JUMPX)
+OPDEF(JSOP_ANDX, 143,"andx", NULL, 5, 1, 0, 0, JOF_JUMPX)
+OPDEF(JSOP_GOSUBX, 144,"gosubx", NULL, 5, 0, 1, 0, JOF_JUMPX)
+OPDEF(JSOP_CASEX, 145,"casex", NULL, 5, 1, 0, 0, JOF_JUMPX)
+OPDEF(JSOP_DEFAULTX, 146,"defaultx", NULL, 5, 1, 0, 0, JOF_JUMPX)
+OPDEF(JSOP_TABLESWITCHX, 147,"tableswitchx",NULL, -1, 1, 0, 0, JOF_TABLESWITCHX)
+OPDEF(JSOP_LOOKUPSWITCHX, 148,"lookupswitchx",NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCHX)
+
+/* Placeholders for a real jump opcode set during backpatch chain fixup. */
+OPDEF(JSOP_BACKPATCH, 149,"backpatch",NULL, 3, 0, 0, 0, JOF_JUMP|JOF_BACKPATCH)
+OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch_pop",NULL, 3, 1, 0, 0, JOF_JUMP|JOF_BACKPATCH)
+OPDEF(JSOP_BACKPATCH_PUSH,151,"backpatch_push",NULL, 3, 0, 1, 0, JOF_JUMP|JOF_BACKPATCH)
+
+/* Set and get return value pseudo-register in stack frame. */
+OPDEF(JSOP_SETRVAL, 152,"setrval", NULL, 1, 1, 0, 0, JOF_BYTE)
+OPDEF(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, 0, JOF_BYTE)
diff --git a/src/dom/js/jsosdep.h b/src/dom/js/jsosdep.h
new file mode 100644
index 000000000..c93eee2f1
--- /dev/null
+++ b/src/dom/js/jsosdep.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsosdep_h___
+#define jsosdep_h___
+/*
+ * OS (and machine, and compiler XXX) dependent information.
+ */
+
+#if defined(XP_WIN) || defined(XP_OS2)
+
+#if defined(_WIN32) || defined (XP_OS2)
+#define JS_HAVE_LONG_LONG
+#else
+#undef JS_HAVE_LONG_LONG
+#endif
+#endif /* XP_WIN || XP_OS2 */
+
+#ifdef XP_MAC
+#define JS_HAVE_LONG_LONG
+
+JS_BEGIN_EXTERN_C
+
+#include <stddef.h>
+
+extern void* reallocSmaller(void* block, size_t newSize);
+
+extern char* strdup(const char* str);
+
+JS_END_EXTERN_C
+
+#endif /* XP_MAC */
+
+#ifdef XP_BEOS
+#define JS_HAVE_LONG_LONG
+#endif
+
+
+#ifdef XP_UNIX
+
+/*
+ * Get OS specific header information.
+ */
+#if defined(AIXV3) || defined(AIX)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(BSDI)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(HPUX)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(IRIX)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(linux)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(OSF1)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(_SCO_DS)
+#undef JS_HAVE_LONG_LONG
+
+#elif defined(SOLARIS)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(FREEBSD)
+#define JS_HAVE_LONG_LONG
+
+#elif defined(SUNOS4)
+#undef JS_HAVE_LONG_LONG
+
+/*
+** Missing function prototypes
+*/
+
+extern void *sbrk(int);
+
+#elif defined(UNIXWARE)
+#undef JS_HAVE_LONG_LONG
+
+#elif defined(VMS) && defined(__ALPHA)
+#define JS_HAVE_LONG_LONG
+
+#endif
+
+#endif /* XP_UNIX */
+
+#endif /* jsosdep_h___ */
+
diff --git a/src/dom/js/jsotypes.h b/src/dom/js/jsotypes.h
new file mode 100644
index 000000000..ad8b5203e
--- /dev/null
+++ b/src/dom/js/jsotypes.h
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * This section typedefs the old 'native' types to the new PR<type>s.
+ * These definitions are scheduled to be eliminated at the earliest
+ * possible time. The NSPR API is implemented and documented using
+ * the new definitions.
+ */
+
+/*
+ * Note that we test for PROTYPES_H, not JSOTYPES_H. This is to avoid
+ * double-definitions of scalar types such as uint32, if NSPR's
+ * protypes.h is also included.
+ */
+#ifndef PROTYPES_H
+#define PROTYPES_H
+
+#ifdef XP_BEOS
+/* BeOS defines most int types in SupportDefs.h (int8, uint8, int16,
+ * uint16, int32, uint32, int64, uint64), so in the interest of
+ * not conflicting with other definitions elsewhere we have to skip the
+ * #ifdef jungle below, duplicate some definitions, and do our stuff.
+ */
+#include <SupportDefs.h>
+
+typedef JSUintn uintn;
+#ifndef _XP_Core_
+typedef JSIntn intn;
+#endif
+
+#else
+
+/* SVR4 typedef of uint is commonly found on UNIX machines. */
+#ifdef XP_UNIX
+#include <sys/types.h>
+#else
+typedef JSUintn uint;
+#endif
+
+typedef JSUintn uintn;
+typedef JSUint64 uint64;
+#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2)
+typedef JSUint32 uint32;
+#else
+typedef unsigned long uint32;
+#endif
+typedef JSUint16 uint16;
+typedef JSUint8 uint8;
+
+#ifndef _XP_Core_
+typedef JSIntn intn;
+#endif
+
+/*
+ * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h, a very
+ * common header file) defines the types int8, int16, int32, and int64.
+ * So we don't define these four types here to avoid conflicts in case
+ * the code also includes sys/types.h.
+ */
+#if defined(AIX) && defined(HAVE_SYS_INTTYPES_H)
+#include <sys/inttypes.h>
+#else
+typedef JSInt64 int64;
+
+/* /usr/include/model.h on HP-UX defines int8, int16, and int32 */
+#ifdef HPUX
+#include <model.h>
+#else
+#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2)
+typedef JSInt32 int32;
+#else
+typedef long int32;
+#endif
+typedef JSInt16 int16;
+typedef JSInt8 int8;
+#endif /* HPUX */
+#endif /* AIX && HAVE_SYS_INTTYPES_H */
+
+#endif /* XP_BEOS */
+
+typedef JSFloat64 float64;
+
+/* Re: jsbit.h */
+#define TEST_BIT JS_TEST_BIT
+#define SET_BIT JS_SET_BIT
+#define CLEAR_BIT JS_CLEAR_BIT
+
+/* Re: prarena.h->plarena.h */
+#define PRArena PLArena
+#define PRArenaPool PLArenaPool
+#define PRArenaStats PLArenaStats
+#define PR_ARENA_ALIGN PL_ARENA_ALIGN
+#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL
+#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE
+#define PR_ARENA_GROW PL_ARENA_GROW
+#define PR_ARENA_MARK PL_ARENA_MARK
+#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED
+#define PR_CLEAR_ARENA PL_CLEAR_ARENA
+#define PR_ARENA_RELEASE PL_ARENA_RELEASE
+#define PR_COUNT_ARENA PL_COUNT_ARENA
+#define PR_ARENA_DESTROY PL_ARENA_DESTROY
+#define PR_InitArenaPool PL_InitArenaPool
+#define PR_FreeArenaPool PL_FreeArenaPool
+#define PR_FinishArenaPool PL_FinishArenaPool
+#define PR_CompactArenaPool PL_CompactArenaPool
+#define PR_ArenaFinish PL_ArenaFinish
+#define PR_ArenaAllocate PL_ArenaAllocate
+#define PR_ArenaGrow PL_ArenaGrow
+#define PR_ArenaRelease PL_ArenaRelease
+#define PR_ArenaCountAllocation PL_ArenaCountAllocation
+#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth
+#define PR_ArenaCountGrowth PL_ArenaCountGrowth
+#define PR_ArenaCountRelease PL_ArenaCountRelease
+#define PR_ArenaCountRetract PL_ArenaCountRetract
+
+/* Re: prevent.h->plevent.h */
+#define PREvent PLEvent
+#define PREventQueue PLEventQueue
+#define PR_CreateEventQueue PL_CreateEventQueue
+#define PR_DestroyEventQueue PL_DestroyEventQueue
+#define PR_GetEventQueueMonitor PL_GetEventQueueMonitor
+#define PR_ENTER_EVENT_QUEUE_MONITOR PL_ENTER_EVENT_QUEUE_MONITOR
+#define PR_EXIT_EVENT_QUEUE_MONITOR PL_EXIT_EVENT_QUEUE_MONITOR
+#define PR_PostEvent PL_PostEvent
+#define PR_PostSynchronousEvent PL_PostSynchronousEvent
+#define PR_GetEvent PL_GetEvent
+#define PR_EventAvailable PL_EventAvailable
+#define PREventFunProc PLEventFunProc
+#define PR_MapEvents PL_MapEvents
+#define PR_RevokeEvents PL_RevokeEvents
+#define PR_ProcessPendingEvents PL_ProcessPendingEvents
+#define PR_WaitForEvent PL_WaitForEvent
+#define PR_EventLoop PL_EventLoop
+#define PR_GetEventQueueSelectFD PL_GetEventQueueSelectFD
+#define PRHandleEventProc PLHandleEventProc
+#define PRDestroyEventProc PLDestroyEventProc
+#define PR_InitEvent PL_InitEvent
+#define PR_GetEventOwner PL_GetEventOwner
+#define PR_HandleEvent PL_HandleEvent
+#define PR_DestroyEvent PL_DestroyEvent
+#define PR_DequeueEvent PL_DequeueEvent
+#define PR_GetMainEventQueue PL_GetMainEventQueue
+
+/* Re: prhash.h->plhash.h */
+#define PRHashEntry PLHashEntry
+#define PRHashTable PLHashTable
+#define PRHashNumber PLHashNumber
+#define PRHashFunction PLHashFunction
+#define PRHashComparator PLHashComparator
+#define PRHashEnumerator PLHashEnumerator
+#define PRHashAllocOps PLHashAllocOps
+#define PR_NewHashTable PL_NewHashTable
+#define PR_HashTableDestroy PL_HashTableDestroy
+#define PR_HashTableRawLookup PL_HashTableRawLookup
+#define PR_HashTableRawAdd PL_HashTableRawAdd
+#define PR_HashTableRawRemove PL_HashTableRawRemove
+#define PR_HashTableAdd PL_HashTableAdd
+#define PR_HashTableRemove PL_HashTableRemove
+#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries
+#define PR_HashTableLookup PL_HashTableLookup
+#define PR_HashTableDump PL_HashTableDump
+#define PR_HashString PL_HashString
+#define PR_CompareStrings PL_CompareStrings
+#define PR_CompareValues PL_CompareValues
+
+#ifdef XP_MAC
+#ifndef TRUE /* Mac standard is lower case true */
+ #define TRUE 1
+#endif
+#ifndef FALSE /* Mac standard is lower case false */
+ #define FALSE 0
+#endif
+#endif
+
+#endif /* !defined(PROTYPES_H) */
diff --git a/src/dom/js/jsparse.c b/src/dom/js/jsparse.c
new file mode 100644
index 000000000..7cf18d454
--- /dev/null
+++ b/src/dom/js/jsparse.c
@@ -0,0 +1,3547 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS parser.
+ *
+ * This is a recursive-descent parser for the JavaScript language specified by
+ * "The JavaScript 1.5 Language Specification". It uses lexical and semantic
+ * feedback to disambiguate non-LL(1) structures. It generates trees of nodes
+ * induced by the recursive parsing (not precise syntax trees, see jsparse.h).
+ * After tree construction, it rewrites trees to fold constants and evaluate
+ * compile-time expressions. Finally, it calls js_EmitTree (see jsemit.h) to
+ * generate bytecode.
+ *
+ * This parser attempts no error recovery. The dense JSTokenType enumeration
+ * was designed with error recovery built on 64-bit first and follow bitsets
+ * in mind, however.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsemit.h"
+#include "jsfun.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsparse.h"
+#include "jsscan.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+/*
+ * JS parsers, from lowest to highest precedence.
+ *
+ * Each parser takes a context and a token stream, and emits bytecode using
+ * a code generator.
+ */
+
+typedef JSParseNode *
+JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc);
+
+typedef JSParseNode *
+JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
+ JSBool allowCallSyntax);
+
+static JSParser FunctionStmt;
+#if JS_HAS_LEXICAL_CLOSURE
+static JSParser FunctionExpr;
+#endif
+static JSParser Statements;
+static JSParser Statement;
+static JSParser Variables;
+static JSParser Expr;
+static JSParser AssignExpr;
+static JSParser CondExpr;
+static JSParser OrExpr;
+static JSParser AndExpr;
+static JSParser BitOrExpr;
+static JSParser BitXorExpr;
+static JSParser BitAndExpr;
+static JSParser EqExpr;
+static JSParser RelExpr;
+static JSParser ShiftExpr;
+static JSParser AddExpr;
+static JSParser MulExpr;
+static JSParser UnaryExpr;
+static JSMemberParser MemberExpr;
+static JSParser PrimaryExpr;
+
+/*
+ * Insist that the next token be of type tt, or report errno and return null.
+ * NB: this macro uses cx and ts from its lexical environment.
+ */
+#define MUST_MATCH_TOKEN(tt, errno) \
+ JS_BEGIN_MACRO \
+ if (js_GetToken(cx, ts) != tt) { \
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, errno); \
+ return NULL; \
+ } \
+ JS_END_MACRO
+
+#define CHECK_RECURSION() \
+ JS_BEGIN_MACRO \
+ int stackDummy; \
+ if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { \
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, \
+ JSMSG_OVER_RECURSED); \
+ return NULL; \
+ } \
+ JS_END_MACRO
+
+#ifdef METER_PARSENODES
+static uint32 parsenodes = 0;
+static uint32 maxparsenodes = 0;
+static uint32 recyclednodes = 0;
+#endif
+
+static void
+RecycleTree(JSParseNode *pn, JSTreeContext *tc)
+{
+ if (!pn)
+ return;
+ JS_ASSERT(pn != tc->nodeList); /* catch back-to-back dup recycles */
+ pn->pn_next = tc->nodeList;
+ tc->nodeList = pn;
+#ifdef METER_PARSENODES
+ recyclednodes++;
+#endif
+}
+
+static JSParseNode *
+NewOrRecycledNode(JSContext *cx, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+
+ pn = tc->nodeList;
+ if (!pn) {
+ JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);
+ if (!pn)
+ JS_ReportOutOfMemory(cx);
+ } else {
+ tc->nodeList = pn->pn_next;
+
+ /* Recycle immediate descendents only, to save work and working set. */
+ switch (pn->pn_arity) {
+ case PN_FUNC:
+ RecycleTree(pn->pn_body, tc);
+ break;
+ case PN_LIST:
+ if (pn->pn_head) {
+ /* XXX check for dup recycles in the list */
+ *pn->pn_tail = tc->nodeList;
+ tc->nodeList = pn->pn_head;
+#ifdef METER_PARSENODES
+ recyclednodes += pn->pn_count;
+#endif
+ }
+ break;
+ case PN_TERNARY:
+ RecycleTree(pn->pn_kid1, tc);
+ RecycleTree(pn->pn_kid2, tc);
+ RecycleTree(pn->pn_kid3, tc);
+ break;
+ case PN_BINARY:
+ RecycleTree(pn->pn_left, tc);
+ RecycleTree(pn->pn_right, tc);
+ break;
+ case PN_UNARY:
+ RecycleTree(pn->pn_kid, tc);
+ break;
+ case PN_NAME:
+ RecycleTree(pn->pn_expr, tc);
+ break;
+ case PN_NULLARY:
+ break;
+ }
+ }
+ return pn;
+}
+
+/*
+ * Allocate a JSParseNode from cx's temporary arena.
+ */
+static JSParseNode *
+NewParseNode(JSContext *cx, JSToken *tok, JSParseNodeArity arity,
+ JSTreeContext *tc)
+{
+ JSParseNode *pn;
+
+ pn = NewOrRecycledNode(cx, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = tok->type;
+ pn->pn_pos = tok->pos;
+ pn->pn_op = JSOP_NOP;
+ pn->pn_arity = arity;
+ pn->pn_next = NULL;
+#ifdef METER_PARSENODES
+ parsenodes++;
+ if (parsenodes - recyclednodes > maxparsenodes)
+ maxparsenodes = parsenodes - recyclednodes;
+#endif
+ return pn;
+}
+
+static JSParseNode *
+NewBinary(JSContext *cx, JSTokenType tt,
+ JSOp op, JSParseNode *left, JSParseNode *right,
+ JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn1, *pn2;
+
+ if (!left || !right)
+ return NULL;
+
+ /*
+ * Flatten a left-associative (left-heavy) tree of a given operator into
+ * a list, to reduce js_FoldConstants and js_EmitTree recursion.
+ */
+ if (left->pn_type == tt &&
+ left->pn_op == op &&
+ (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
+ if (left->pn_arity != PN_LIST) {
+ pn1 = left->pn_left, pn2 = left->pn_right;
+ left->pn_arity = PN_LIST;
+ PN_INIT_LIST_1(left, pn1);
+ PN_APPEND(left, pn2);
+ left->pn_extra = 0;
+ if (tt == TOK_PLUS) {
+ if (pn1->pn_type == TOK_STRING)
+ left->pn_extra |= PNX_STRCAT;
+ else if (pn1->pn_type != TOK_NUMBER)
+ left->pn_extra |= PNX_CANTFOLD;
+ if (pn2->pn_type == TOK_STRING)
+ left->pn_extra |= PNX_STRCAT;
+ else if (pn2->pn_type != TOK_NUMBER)
+ left->pn_extra |= PNX_CANTFOLD;
+ }
+ }
+ PN_APPEND(left, right);
+ left->pn_pos.end = right->pn_pos.end;
+ if (tt == TOK_PLUS) {
+ if (right->pn_type == TOK_STRING)
+ left->pn_extra |= PNX_STRCAT;
+ else if (right->pn_type != TOK_NUMBER)
+ left->pn_extra |= PNX_CANTFOLD;
+ }
+ return left;
+ }
+
+ /*
+ * Fold constant addition immediately, to conserve node space and, what's
+ * more, so js_FoldConstants never sees mixed addition and concatenation
+ * operations with more than one leading non-string operand in a PN_LIST
+ * generated for expressions such as 1 + 2 + "pt" (which should evaluate
+ * to "3pt", not "12pt").
+ */
+ if (tt == TOK_PLUS &&
+ left->pn_type == TOK_NUMBER &&
+ right->pn_type == TOK_NUMBER) {
+ left->pn_dval += right->pn_dval;
+ RecycleTree(right, tc);
+ return left;
+ }
+
+ pn = NewOrRecycledNode(cx, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = tt;
+ pn->pn_pos.begin = left->pn_pos.begin;
+ pn->pn_pos.end = right->pn_pos.end;
+ pn->pn_op = op;
+ pn->pn_arity = PN_BINARY;
+ pn->pn_left = left;
+ pn->pn_right = right;
+ pn->pn_next = NULL;
+#ifdef METER_PARSENODES
+ parsenodes++;
+ if (parsenodes - recyclednodes > maxparsenodes)
+ maxparsenodes = parsenodes - recyclednodes;
+#endif
+ return pn;
+}
+
+#if JS_HAS_GETTER_SETTER
+static JSTokenType
+CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
+{
+ JSAtom *atom;
+ JSRuntime *rt;
+ JSOp op;
+ const char *name;
+
+ JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_NAME);
+ atom = CURRENT_TOKEN(ts).t_atom;
+ rt = cx->runtime;
+ if (atom == rt->atomState.getterAtom)
+ op = JSOP_GETTER;
+ else if (atom == rt->atomState.setterAtom)
+ op = JSOP_SETTER;
+ else
+ return TOK_NAME;
+ if (js_PeekTokenSameLine(cx, ts) != tt)
+ return TOK_NAME;
+ (void) js_GetToken(cx, ts);
+ if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_GETTER_OR_SETTER,
+ (op == JSOP_GETTER)
+ ? js_getter_str
+ : js_setter_str);
+ return TOK_ERROR;
+ }
+ CURRENT_TOKEN(ts).t_op = op;
+ name = js_AtomToPrintableString(cx, atom);
+ if (!name ||
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_DEPRECATED_USAGE,
+ name)) {
+ return TOK_ERROR;
+ }
+ return tt;
+}
+#endif
+
+/*
+ * Parse a top-level JS script.
+ */
+JS_FRIEND_API(JSParseNode *)
+js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts)
+{
+ JSStackFrame *fp, frame;
+ JSTreeContext tc;
+ JSParseNode *pn;
+
+ /*
+ * Push a compiler frame if we have no frames, or if the top frame is a
+ * lightweight function activation, or if its scope chain doesn't match
+ * the one passed to us.
+ */
+ fp = cx->fp;
+ if (!fp || !fp->varobj || fp->scopeChain != chain) {
+ memset(&frame, 0, sizeof frame);
+ frame.varobj = frame.scopeChain = chain;
+ if (cx->options & JSOPTION_VAROBJFIX) {
+ while ((chain = JS_GetParent(cx, chain)) != NULL)
+ frame.varobj = chain;
+ }
+ frame.down = fp;
+ cx->fp = &frame;
+ }
+
+ /*
+ * Protect atoms from being collected by a GC activation, which might
+ * - nest on this thread due to out of memory (the so-called "last ditch"
+ * GC attempted within js_AllocGCThing), or
+ * - run for any reason on another thread if this thread is suspended on
+ * an object lock before it finishes generating bytecode into a script
+ * protected from the GC by a root or a stack frame reference.
+ */
+ JS_KEEP_ATOMS(cx->runtime);
+ TREE_CONTEXT_INIT(&tc);
+ pn = Statements(cx, ts, &tc);
+ if (pn) {
+ if (!js_MatchToken(cx, ts, TOK_EOF)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_SYNTAX_ERROR);
+ pn = NULL;
+ } else {
+ pn->pn_type = TOK_LC;
+ if (!js_FoldConstants(cx, pn, &tc))
+ pn = NULL;
+ }
+ }
+
+ TREE_CONTEXT_FINISH(&tc);
+ JS_UNKEEP_ATOMS(cx->runtime);
+ cx->fp = fp;
+ return pn;
+}
+
+/*
+ * Compile a top-level script.
+ */
+JS_FRIEND_API(JSBool)
+js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
+ JSCodeGenerator *cg)
+{
+ JSStackFrame *fp, frame;
+ JSParseNode *pn;
+ JSBool ok;
+#ifdef METER_PARSENODES
+ void *sbrk(ptrdiff_t), *before = sbrk(0);
+#endif
+
+ /*
+ * Push a compiler frame if we have no frames, or if the top frame is a
+ * lightweight function activation, or if its scope chain doesn't match
+ * the one passed to us.
+ */
+ fp = cx->fp;
+ if (!fp || !fp->varobj || fp->scopeChain != chain) {
+ memset(&frame, 0, sizeof frame);
+ frame.varobj = frame.scopeChain = chain;
+ if (cx->options & JSOPTION_VAROBJFIX) {
+ while ((chain = JS_GetParent(cx, chain)) != NULL)
+ frame.varobj = chain;
+ }
+ frame.down = fp;
+ cx->fp = &frame;
+ }
+
+ /* Prevent GC activation while compiling. */
+ JS_KEEP_ATOMS(cx->runtime);
+
+ pn = Statements(cx, ts, &cg->treeContext);
+ if (!pn) {
+ ok = JS_FALSE;
+ } else if (!js_MatchToken(cx, ts, TOK_EOF)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_SYNTAX_ERROR);
+ ok = JS_FALSE;
+ } else {
+#ifdef METER_PARSENODES
+ printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",
+ (char *)sbrk(0) - (char *)before,
+ parsenodes,
+ maxparsenodes,
+ parsenodes - recyclednodes);
+ before = sbrk(0);
+#endif
+
+ /*
+ * No need to emit code here -- Statements already has, for each
+ * statement in turn. Search for TCF_COMPILING in Statements, below.
+ * That flag is set for every tc == &cg->treeContext, and it implies
+ * that the tc can be downcast to a cg and used to emit code during
+ * parsing, rather than at the end of the parse phase.
+ */
+ JS_ASSERT(cg->treeContext.flags & TCF_COMPILING);
+ ok = JS_TRUE;
+ }
+
+#ifdef METER_PARSENODES
+ printf("Code-gen growth: %d (%u bytecodes, %u srcnotes)\n",
+ (char *)sbrk(0) - (char *)before, CG_OFFSET(cg), cg->noteCount);
+#endif
+#ifdef JS_ARENAMETER
+ JS_DumpArenaStats(stdout);
+#endif
+ JS_UNKEEP_ATOMS(cx->runtime);
+ cx->fp = fp;
+ return ok;
+}
+
+/*
+ * Insist on a final return before control flows out of pn, but don't be too
+ * smart about loops (do {...; return e2;} while(0) at the end of a function
+ * that contains an early return e1 will get a strict-option-only warning).
+ */
+static JSBool
+HasFinalReturn(JSParseNode *pn)
+{
+ JSBool ok, hasDefault;
+ JSParseNode *pn2, *pn3;
+
+ switch (pn->pn_type) {
+ case TOK_LC:
+ if (!pn->pn_head)
+ return JS_FALSE;
+ return HasFinalReturn(PN_LAST(pn));
+
+ case TOK_IF:
+ ok = HasFinalReturn(pn->pn_kid2);
+ ok &= pn->pn_kid3 && HasFinalReturn(pn->pn_kid3);
+ return ok;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case TOK_SWITCH:
+ ok = JS_TRUE;
+ hasDefault = JS_FALSE;
+ for (pn2 = pn->pn_kid2->pn_head; ok && pn2; pn2 = pn2->pn_next) {
+ if (pn2->pn_type == TOK_DEFAULT)
+ hasDefault = JS_TRUE;
+ pn3 = pn2->pn_right;
+ JS_ASSERT(pn3->pn_type == TOK_LC);
+ if (pn3->pn_head)
+ ok &= HasFinalReturn(PN_LAST(pn3));
+ }
+ /* If a final switch has no default case, we judge it harshly. */
+ ok &= hasDefault;
+ return ok;
+#endif /* JS_HAS_SWITCH_STATEMENT */
+
+ case TOK_WITH:
+ return HasFinalReturn(pn->pn_right);
+
+ case TOK_RETURN:
+ return JS_TRUE;
+
+#if JS_HAS_EXCEPTIONS
+ case TOK_THROW:
+ return JS_TRUE;
+
+ case TOK_TRY:
+ /* If we have a finally block that returns, we are done. */
+ if (pn->pn_kid3 && HasFinalReturn(pn->pn_kid3))
+ return JS_TRUE;
+
+ /* Else check the try block and any and all catch statements. */
+ ok = HasFinalReturn(pn->pn_kid1);
+ if (pn->pn_kid2)
+ ok &= HasFinalReturn(pn->pn_kid2);
+ return ok;
+
+ case TOK_CATCH:
+ /* Check this block's code and iterate over further catch blocks. */
+ ok = HasFinalReturn(pn->pn_kid3);
+ for (pn2 = pn->pn_kid2; pn2; pn2 = pn2->pn_kid2)
+ ok &= HasFinalReturn(pn2->pn_kid3);
+ return ok;
+#endif
+
+ default:
+ return JS_FALSE;
+ }
+}
+
+static JSBool
+ReportNoReturnValue(JSContext *cx, JSTokenStream *ts)
+{
+ JSFunction *fun;
+ JSBool ok;
+
+ fun = cx->fp->fun;
+ if (fun->atom) {
+ char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));
+ ok = js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_NO_RETURN_VALUE, name);
+ } else {
+ ok = js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_ANON_NO_RETURN_VALUE);
+ }
+ return ok;
+}
+
+static JSBool
+CheckFinalReturn(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
+{
+ return HasFinalReturn(pn) || ReportNoReturnValue(cx, ts);
+}
+
+static JSParseNode *
+FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
+ JSTreeContext *tc)
+{
+ JSStackFrame *fp, frame;
+ JSObject *funobj;
+ uintN oldflags;
+ JSParseNode *pn;
+
+ fp = cx->fp;
+ funobj = fun->object;
+ if (!fp || fp->fun != fun || fp->varobj != funobj ||
+ fp->scopeChain != funobj) {
+ memset(&frame, 0, sizeof frame);
+ frame.fun = fun;
+ frame.varobj = frame.scopeChain = funobj;
+ frame.down = fp;
+ cx->fp = &frame;
+ }
+
+ oldflags = tc->flags;
+ tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
+ tc->flags |= TCF_IN_FUNCTION;
+ pn = Statements(cx, ts, tc);
+
+ /* Check for falling off the end of a function that returns a value. */
+ if (pn && JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {
+ if (!CheckFinalReturn(cx, ts, pn))
+ pn = NULL;
+ }
+
+ cx->fp = fp;
+ tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
+ return pn;
+}
+
+/*
+ * Compile a JS function body, which might appear as the value of an event
+ * handler attribute in an HTML <INPUT> tag.
+ */
+JSBool
+js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
+{
+ JSArenaPool codePool, notePool;
+ JSCodeGenerator funcg;
+ JSStackFrame *fp, frame;
+ JSObject *funobj;
+ JSParseNode *pn;
+ JSBool ok;
+
+ JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
+ JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));
+ if (!js_InitCodeGenerator(cx, &funcg, &codePool, &notePool,
+ ts->filename, ts->lineno,
+ ts->principals)) {
+ return JS_FALSE;
+ }
+
+ /* Prevent GC activation while compiling. */
+ JS_KEEP_ATOMS(cx->runtime);
+
+ /* Push a JSStackFrame for use by FunctionBody and js_EmitFunctionBody. */
+ fp = cx->fp;
+ funobj = fun->object;
+ JS_ASSERT(!fp || fp->fun != fun || fp->varobj != funobj ||
+ fp->scopeChain != funobj);
+ memset(&frame, 0, sizeof frame);
+ frame.fun = fun;
+ frame.varobj = frame.scopeChain = funobj;
+ frame.down = fp;
+ cx->fp = &frame;
+
+ /* Ensure that the body looks like a block statement to js_EmitTree. */
+ CURRENT_TOKEN(ts).type = TOK_LC;
+ pn = FunctionBody(cx, ts, fun, &funcg.treeContext);
+ if (!pn) {
+ ok = JS_FALSE;
+ } else {
+ /*
+ * No need to emit code here -- Statements (via FunctionBody) already
+ * has. See similar comment in js_CompileTokenStream, and bug 108257.
+ */
+ fun->script = js_NewScriptFromCG(cx, &funcg, fun);
+ if (!fun->script) {
+ ok = JS_FALSE;
+ } else {
+ if (funcg.treeContext.flags & TCF_FUN_HEAVYWEIGHT)
+ fun->flags |= JSFUN_HEAVYWEIGHT;
+ ok = JS_TRUE;
+ }
+ }
+
+ /* Restore saved state and release code generation arenas. */
+ cx->fp = fp;
+ JS_UNKEEP_ATOMS(cx->runtime);
+ js_FinishCodeGenerator(cx, &funcg);
+ JS_FinishArenaPool(&codePool);
+ JS_FinishArenaPool(&notePool);
+ return ok;
+}
+
+static JSParseNode *
+FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
+ JSBool lambda)
+{
+ JSParseNode *pn, *body;
+ JSOp op, prevop;
+ JSAtom *funAtom, *argAtom;
+ JSFunction *fun;
+ JSObject *parent;
+ JSObject *pobj;
+ JSScopeProperty *sprop;
+ uintN dupflag;
+ JSBool ok;
+ JSTreeContext funtc;
+ JSAtomListElement *ale;
+
+ /* Make a TOK_FUNCTION node. */
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC, tc);
+ if (!pn)
+ return NULL;
+#if JS_HAS_GETTER_SETTER
+ op = CURRENT_TOKEN(ts).t_op;
+#endif
+
+ /* Scan the optional function name into funAtom. */
+ if (js_MatchToken(cx, ts, TOK_NAME))
+ funAtom = CURRENT_TOKEN(ts).t_atom;
+ else
+ funAtom = NULL;
+
+ /* Find the nearest variable-declaring scope and use it as our parent. */
+ parent = cx->fp->varobj;
+ fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, parent,
+ funAtom);
+ if (!fun)
+ return NULL;
+
+#if JS_HAS_GETTER_SETTER
+ if (op != JSOP_NOP)
+ fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
+#endif
+
+ /* Now parse formal argument list and compute fun->nargs. */
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
+ if (!js_MatchToken(cx, ts, TOK_RP)) {
+ do {
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_MISSING_FORMAL);
+ argAtom = CURRENT_TOKEN(ts).t_atom;
+ pobj = NULL;
+ if (!js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
+ (JSProperty **)&sprop)) {
+ return NULL;
+ }
+ dupflag = 0;
+ if (sprop) {
+ ok = JS_TRUE;
+ if (pobj == fun->object &&
+ sprop->getter == js_GetArgument) {
+ const char *name = js_AtomToPrintableString(cx, argAtom);
+
+ /*
+ * A duplicate parameter name. We force a duplicate node
+ * on the SCOPE_LAST_PROP(scope) list with the same id,
+ * distinguished by the SPROP_IS_DUPLICATE flag, and not
+ * mapped by an entry in scope.
+ */
+ ok = name &&
+ js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_DUPLICATE_FORMAL,
+ name);
+
+ dupflag = SPROP_IS_DUPLICATE;
+ }
+ OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
+ if (!ok)
+ return NULL;
+ sprop = NULL;
+ }
+ if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
+ js_GetArgument, js_SetArgument,
+ SPROP_INVALID_SLOT,
+ JSPROP_ENUMERATE | JSPROP_PERMANENT |
+ JSPROP_SHARED,
+ SPROP_HAS_SHORTID | dupflag,
+ fun->nargs)) {
+ return NULL;
+ }
+ fun->nargs++;
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
+
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL);
+ }
+
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
+ pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin;
+
+ TREE_CONTEXT_INIT(&funtc);
+ body = FunctionBody(cx, ts, fun, &funtc);
+ if (!body)
+ return NULL;
+
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+
+#if JS_HAS_LEXICAL_CLOSURE
+ /*
+ * If we collected flags that indicate nested heavyweight functions, or
+ * this function contains heavyweight-making statements (references to
+ * __parent__ or __proto__; use of with, eval, import, or export; and
+ * assignment to arguments), flag the function as heavyweight (requiring
+ * a call object per invocation).
+ */
+ if (funtc.flags & TCF_FUN_HEAVYWEIGHT) {
+ fun->flags |= JSFUN_HEAVYWEIGHT;
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ } else {
+ /*
+ * If this function is a named statement function not at top-level
+ * (i.e. a JSOP_CLOSURE), or if it refers to unqualified names that
+ * are not local args or vars (TCF_FUN_USES_NONLOCALS), then our
+ * enclosing function, if any, must be heavyweight.
+ */
+ if ((!lambda && funAtom && tc->topStmt) ||
+ (funtc.flags & TCF_FUN_USES_NONLOCALS)) {
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ }
+ }
+#endif
+
+ /*
+ * Record names for function statements in tc->decls so we know when to
+ * avoid optimizing variable references that might name a function.
+ */
+ if (!lambda && funAtom) {
+ ATOM_LIST_SEARCH(ale, &tc->decls, funAtom);
+ if (ale) {
+ prevop = ALE_JSOP(ale);
+ if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) {
+ const char *name = js_AtomToPrintableString(cx, funAtom);
+ if (!name ||
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
+ (prevop != JSOP_DEFCONST)
+ ? JSREPORT_WARNING |
+ JSREPORT_STRICT
+ : JSREPORT_ERROR,
+ JSMSG_REDECLARED_VAR,
+ (prevop == JSOP_DEFFUN ||
+ prevop == JSOP_CLOSURE)
+ ? js_function_str
+ : (prevop == JSOP_DEFCONST)
+ ? js_const_str
+ : js_var_str,
+ name)) {
+ return NULL;
+ }
+ }
+ if (tc->topStmt && prevop == JSOP_DEFVAR)
+ tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
+ } else {
+ ale = js_IndexAtom(cx, funAtom, &tc->decls);
+ if (!ale)
+ return NULL;
+ }
+ ALE_SET_JSOP(ale, tc->topStmt ? JSOP_CLOSURE : JSOP_DEFFUN);
+
+#if JS_HAS_LEXICAL_CLOSURE
+ /*
+ * A function nested at top level inside another's body needs only a
+ * local variable to bind its name to its value, and not an activation
+ * object property (it might also need the activation property, if the
+ * outer function contains with statements, e.g., but the stack slot
+ * wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a
+ * JSOP_GETVAR bytecode).
+ */
+ if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) {
+ JSStackFrame *fp;
+ JSObject *varobj;
+
+ /*
+ * Define a property on the outer function so that LookupArgOrVar
+ * can properly optimize accesses.
+ *
+ * XXX Here and in Variables, we use the function object's scope,
+ * XXX arguably polluting it, when we could use a compiler-private
+ * XXX scope structure. Tradition!
+ */
+ fp = cx->fp;
+ varobj = fp->varobj;
+ JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
+ JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj));
+ if (!js_DefineNativeProperty(cx, varobj, (jsid)funAtom,
+ OBJECT_TO_JSVAL(fun->object),
+ js_GetLocalVariable,
+ js_SetLocalVariable,
+ JSPROP_ENUMERATE,
+ SPROP_HAS_SHORTID, fp->fun->nvars,
+ NULL)) {
+ return NULL;
+ }
+ fp->fun->nvars++;
+ }
+#endif
+ }
+
+#if JS_HAS_LEXICAL_CLOSURE
+ if (lambda || !funAtom) {
+ /*
+ * ECMA ed. 3 standard: function expression, possibly anonymous (even
+ * if at top-level, an unnamed function is an expression statement, not
+ * a function declaration).
+ */
+ op = fun->atom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;
+ } else if (tc->topStmt) {
+ /*
+ * ECMA ed. 3 extension: a function expression statement not at the
+ * top level, e.g., in a compound statement such as the "then" part
+ * of an "if" statement, binds a closure only if control reaches that
+ * sub-statement.
+ */
+ op = JSOP_CLOSURE;
+ } else
+#endif
+ op = JSOP_NOP;
+
+ /*
+ * Pending a better automatic GC root management scheme (see Mozilla bug
+ * 40757, http://bugzilla.mozilla.org/show_bug.cgi?id=40757), we need to
+ * atomize here to protect against a GC activation.
+ */
+ pn->pn_funAtom = js_AtomizeObject(cx, fun->object, 0);
+ if (!pn->pn_funAtom)
+ return NULL;
+
+ pn->pn_op = op;
+ pn->pn_body = body;
+ pn->pn_flags = funtc.flags & TCF_FUN_FLAGS;
+ pn->pn_tryCount = funtc.tryCount;
+ TREE_CONTEXT_FINISH(&funtc);
+ return pn;
+}
+
+static JSParseNode *
+FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ return FunctionDef(cx, ts, tc, JS_FALSE);
+}
+
+#if JS_HAS_LEXICAL_CLOSURE
+static JSParseNode *
+FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ return FunctionDef(cx, ts, tc, JS_TRUE);
+}
+#endif
+
+/*
+ * Parse the statements in a block, creating a TOK_LC node that lists the
+ * statements' trees. If called from block-parsing code, the caller must
+ * match { before and } after.
+ */
+static JSParseNode *
+Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn2;
+ JSTokenType tt;
+
+ CHECK_RECURSION();
+
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn)
+ return NULL;
+ PN_INIT_LIST(pn);
+
+ ts->flags |= TSF_REGEXP;
+ while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {
+ ts->flags &= ~TSF_REGEXP;
+ pn2 = Statement(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ ts->flags |= TSF_REGEXP;
+
+ /* If compiling top-level statements, emit as we go to save space. */
+ if (!tc->topStmt && (tc->flags & TCF_COMPILING)) {
+ if (cx->fp->fun &&
+ JS_HAS_STRICT_OPTION(cx) &&
+ (tc->flags & TCF_RETURN_EXPR)) {
+ /*
+ * Check pn2 for lack of a final return statement if it is the
+ * last statement in the block.
+ */
+ tt = js_PeekToken(cx, ts);
+ if ((tt == TOK_EOF || tt == TOK_RC) &&
+ !CheckFinalReturn(cx, ts, pn2)) {
+ tt = TOK_ERROR;
+ break;
+ }
+
+ /*
+ * Clear TCF_RETURN_EXPR so FunctionBody doesn't try to
+ * CheckFinalReturn again.
+ */
+ tc->flags &= ~TCF_RETURN_EXPR;
+ }
+ if (!js_FoldConstants(cx, pn2, tc) ||
+ !js_AllocTryNotes(cx, (JSCodeGenerator *)tc) ||
+ !js_EmitTree(cx, (JSCodeGenerator *)tc, pn2)) {
+ tt = TOK_ERROR;
+ break;
+ }
+ RecycleTree(pn2, tc);
+ } else {
+ PN_APPEND(pn, pn2);
+ }
+ }
+ ts->flags &= ~TSF_REGEXP;
+ if (tt == TOK_ERROR)
+ return NULL;
+
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ return pn;
+}
+
+static JSParseNode *
+Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn2;
+
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
+ pn = Expr(cx, ts, tc);
+ if (!pn)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
+
+ /*
+ * Check for (a = b) and "correct" it to (a == b) iff b's operator has
+ * greater precedence than ==.
+ * XXX not ECMA, but documented in several books -- now a strict warning.
+ */
+ if (pn->pn_type == TOK_ASSIGN &&
+ pn->pn_op == JSOP_NOP &&
+ pn->pn_right->pn_type > TOK_EQOP)
+ {
+ JSBool rewrite = !JSVERSION_IS_ECMA(cx->version);
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING | JSREPORT_STRICT,
+ JSMSG_EQUAL_AS_ASSIGN,
+ rewrite
+ ? "\nAssuming equality test"
+ : "")) {
+ return NULL;
+ }
+ if (rewrite) {
+ pn->pn_type = TOK_EQOP;
+ pn->pn_op = (JSOp)cx->jsop_eq;
+ pn2 = pn->pn_left;
+ switch (pn2->pn_op) {
+ case JSOP_SETNAME:
+ pn2->pn_op = JSOP_NAME;
+ break;
+ case JSOP_SETPROP:
+ pn2->pn_op = JSOP_GETPROP;
+ break;
+ case JSOP_SETELEM:
+ pn2->pn_op = JSOP_GETELEM;
+ break;
+ default:
+ JS_ASSERT(0);
+ }
+ }
+ }
+ return pn;
+}
+
+static JSBool
+MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
+{
+ JSAtom *label;
+#if JS_HAS_LABEL_STATEMENT
+ JSTokenType tt;
+
+ tt = js_PeekTokenSameLine(cx, ts);
+ if (tt == TOK_ERROR)
+ return JS_FALSE;
+ if (tt == TOK_NAME) {
+ (void) js_GetToken(cx, ts);
+ label = CURRENT_TOKEN(ts).t_atom;
+ } else {
+ label = NULL;
+ }
+#else
+ label = NULL;
+#endif
+ pn->pn_atom = label;
+ return JS_TRUE;
+}
+
+#if JS_HAS_EXPORT_IMPORT
+static JSParseNode *
+ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn2, *pn3;
+ JSTokenType tt;
+
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_op = JSOP_NAME;
+ pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ pn->pn_expr = NULL;
+ pn->pn_slot = -1;
+ pn->pn_attrs = 0;
+
+ ts->flags |= TSF_REGEXP;
+ while ((tt = js_GetToken(cx, ts)) == TOK_DOT || tt == TOK_LB) {
+ ts->flags &= ~TSF_REGEXP;
+ if (pn->pn_op == JSOP_IMPORTALL)
+ goto bad_import;
+
+ if (tt == TOK_DOT) {
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+ if (!pn2)
+ return NULL;
+ if (js_MatchToken(cx, ts, TOK_STAR)) {
+ pn2->pn_op = JSOP_IMPORTALL;
+ pn2->pn_atom = NULL;
+ } else {
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
+ pn2->pn_op = JSOP_GETPROP;
+ pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ pn2->pn_slot = -1;
+ pn2->pn_attrs = 0;
+ }
+ pn2->pn_expr = pn;
+ pn2->pn_pos.begin = pn->pn_pos.begin;
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ } else {
+ /* Make a TOK_LB node. */
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn2)
+ return NULL;
+ pn3 = Expr(cx, ts, tc);
+ if (!pn3)
+ return NULL;
+
+ MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
+ pn2->pn_pos.begin = pn->pn_pos.begin;
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+
+ pn2->pn_op = JSOP_GETELEM;
+ pn2->pn_left = pn;
+ pn2->pn_right = pn3;
+ }
+
+ pn = pn2;
+ ts->flags |= TSF_REGEXP;
+ }
+ ts->flags &= ~TSF_REGEXP;
+ if (tt == TOK_ERROR)
+ return NULL;
+ js_UngetToken(ts);
+
+ switch (pn->pn_op) {
+ case JSOP_GETPROP:
+ pn->pn_op = JSOP_IMPORTPROP;
+ break;
+ case JSOP_GETELEM:
+ pn->pn_op = JSOP_IMPORTELEM;
+ break;
+ case JSOP_IMPORTALL:
+ break;
+ default:
+ goto bad_import;
+ }
+ return pn;
+
+ bad_import:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_IMPORT);
+ return NULL;
+}
+#endif /* JS_HAS_EXPORT_IMPORT */
+
+extern const char js_with_statement_str[];
+
+static JSParseNode *
+Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSTokenType tt;
+ JSParseNode *pn, *pn1, *pn2, *pn3, *pn4;
+ JSStmtInfo stmtInfo, *stmt, *stmt2;
+ JSAtom *label;
+
+ ts->flags |= TSF_REGEXP;
+ tt = js_GetToken(cx, ts);
+ ts->flags &= ~TSF_REGEXP;
+
+#if JS_HAS_GETTER_SETTER
+ if (tt == TOK_NAME) {
+ tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);
+ if (tt == TOK_ERROR)
+ return NULL;
+ }
+#endif
+
+ switch (tt) {
+#if JS_HAS_EXPORT_IMPORT
+ case TOK_EXPORT:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn)
+ return NULL;
+ PN_INIT_LIST(pn);
+ if (js_MatchToken(cx, ts, TOK_STAR)) {
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn2)
+ return NULL;
+ PN_APPEND(pn, pn2);
+ } else {
+ do {
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_EXPORT_NAME);
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+ if (!pn2)
+ return NULL;
+ pn2->pn_op = JSOP_NAME;
+ pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ pn2->pn_expr = NULL;
+ pn2->pn_slot = -1;
+ pn2->pn_attrs = 0;
+ PN_APPEND(pn, pn2);
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
+ }
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ break;
+
+ case TOK_IMPORT:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn)
+ return NULL;
+ PN_INIT_LIST(pn);
+ do {
+ pn2 = ImportExpr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ PN_APPEND(pn, pn2);
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ break;
+#endif /* JS_HAS_EXPORT_IMPORT */
+
+ case TOK_FUNCTION:
+ return FunctionStmt(cx, ts, tc);
+
+ case TOK_IF:
+ /* An IF node has three kids: condition, then, and optional else. */
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+ if (!pn)
+ return NULL;
+ pn1 = Condition(cx, ts, tc);
+ if (!pn1)
+ return NULL;
+ js_PushStatement(tc, &stmtInfo, STMT_IF, -1);
+ pn2 = Statement(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ if (js_MatchToken(cx, ts, TOK_ELSE)) {
+ stmtInfo.type = STMT_ELSE;
+ pn3 = Statement(cx, ts, tc);
+ if (!pn3)
+ return NULL;
+ pn->pn_pos.end = pn3->pn_pos.end;
+ } else {
+ pn3 = NULL;
+ pn->pn_pos.end = pn2->pn_pos.end;
+ }
+ js_PopStatement(tc);
+ pn->pn_kid1 = pn1;
+ pn->pn_kid2 = pn2;
+ pn->pn_kid3 = pn3;
+ return pn;
+
+#if JS_HAS_SWITCH_STATEMENT
+ case TOK_SWITCH:
+ {
+ JSParseNode *pn5;
+ JSBool seenDefault = JS_FALSE;
+
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
+
+ /* pn1 points to the switch's discriminant. */
+ pn1 = Expr(cx, ts, tc);
+ if (!pn1)
+ return NULL;
+
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
+
+ /* pn2 is a list of case nodes. The default case has pn_left == NULL */
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn2)
+ return NULL;
+ PN_INIT_LIST(pn2);
+
+ js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);
+
+ while ((tt = js_GetToken(cx, ts)) != TOK_RC) {
+ switch (tt) {
+ case TOK_DEFAULT:
+ if (seenDefault) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_TOO_MANY_DEFAULTS);
+ return NULL;
+ }
+ seenDefault = JS_TRUE;
+ /* fall through */
+
+ case TOK_CASE:
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn3)
+ return NULL;
+ if (tt == TOK_DEFAULT) {
+ pn3->pn_left = NULL;
+ } else {
+ pn3->pn_left = Expr(cx, ts, tc);
+ if (!pn3->pn_left)
+ return NULL;
+ }
+ PN_APPEND(pn2, pn3);
+ if (pn2->pn_count == JS_BIT(16)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_TOO_MANY_CASES);
+ return NULL;
+ }
+ break;
+
+ case TOK_ERROR:
+ return NULL;
+
+ default:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_SWITCH);
+ return NULL;
+ }
+ MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
+
+ pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn4)
+ return NULL;
+ pn4->pn_type = TOK_LC;
+ PN_INIT_LIST(pn4);
+ while ((tt = js_PeekToken(cx, ts)) != TOK_RC &&
+ tt != TOK_CASE && tt != TOK_DEFAULT) {
+ if (tt == TOK_ERROR)
+ return NULL;
+ pn5 = Statement(cx, ts, tc);
+ if (!pn5)
+ return NULL;
+ pn4->pn_pos.end = pn5->pn_pos.end;
+ PN_APPEND(pn4, pn5);
+ }
+
+ /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */
+ if (pn4->pn_head)
+ pn4->pn_pos.begin = pn4->pn_head->pn_pos.begin;
+ pn3->pn_pos.end = pn4->pn_pos.end;
+ pn3->pn_right = pn4;
+ }
+
+ js_PopStatement(tc);
+
+ pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ pn->pn_kid1 = pn1;
+ pn->pn_kid2 = pn2;
+ return pn;
+ }
+#endif /* JS_HAS_SWITCH_STATEMENT */
+
+ case TOK_WHILE:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn)
+ return NULL;
+ js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);
+ pn2 = Condition(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ pn->pn_left = pn2;
+ pn2 = Statement(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ js_PopStatement(tc);
+ pn->pn_pos.end = pn2->pn_pos.end;
+ pn->pn_right = pn2;
+ return pn;
+
+#if JS_HAS_DO_WHILE_LOOP
+ case TOK_DO:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn)
+ return NULL;
+ js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
+ pn2 = Statement(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ pn->pn_left = pn2;
+ MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
+ pn2 = Condition(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ js_PopStatement(tc);
+ pn->pn_pos.end = pn2->pn_pos.end;
+ pn->pn_right = pn2;
+ break;
+#endif /* JS_HAS_DO_WHILE_LOOP */
+
+ case TOK_FOR:
+ /* A FOR node is binary, left is loop control and right is the body. */
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn)
+ return NULL;
+ js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);
+
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
+ tt = js_PeekToken(cx, ts);
+ if (tt == TOK_SEMI) {
+ /* No initializer -- set first kid of left sub-node to null. */
+ pn1 = NULL;
+ } else {
+ /* Set pn1 to a var list or an initializing expression. */
+#if JS_HAS_IN_OPERATOR
+ /*
+ * Set the TCF_IN_FOR_INIT flag during parsing of the first clause
+ * of the for statement. This flag will be used by the RelExpr
+ * production; if it is set, then the 'in' keyword will not be
+ * recognized as an operator, leaving it available to be parsed as
+ * part of a for/in loop. A side effect of this restriction is
+ * that (unparenthesized) expressions involving an 'in' operator
+ * are illegal in the init clause of an ordinary for loop.
+ */
+ tc->flags |= TCF_IN_FOR_INIT;
+#endif /* JS_HAS_IN_OPERATOR */
+ if (tt == TOK_VAR) {
+ (void) js_GetToken(cx, ts);
+ pn1 = Variables(cx, ts, tc);
+ } else {
+ pn1 = Expr(cx, ts, tc);
+ }
+#if JS_HAS_IN_OPERATOR
+ tc->flags &= ~TCF_IN_FOR_INIT;
+#endif /* JS_HAS_IN_OPERATOR */
+ if (!pn1)
+ return NULL;
+ }
+
+ /*
+ * We can be sure that it's a for/in loop if there's still an 'in'
+ * keyword here, even if JavaScript recognizes 'in' as an operator,
+ * as we've excluded 'in' from being parsed in RelExpr by setting
+ * the TCF_IN_FOR_INIT flag in our JSTreeContext.
+ */
+ if (pn1 && js_MatchToken(cx, ts, TOK_IN)) {
+ stmtInfo.type = STMT_FOR_IN_LOOP;
+
+ /* Check that the left side of the 'in' is valid. */
+ if ((pn1->pn_type == TOK_VAR)
+ ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST)
+ : (pn1->pn_type != TOK_NAME &&
+ pn1->pn_type != TOK_DOT &&
+ pn1->pn_type != TOK_LB)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_FOR_LEFTSIDE);
+ return NULL;
+ }
+
+ if (pn1->pn_type == TOK_VAR) {
+ /* Tell js_EmitTree(TOK_VAR) to generate a final POP. */
+ pn1->pn_extra = JS_TRUE;
+ pn2 = pn1->pn_head;
+ } else {
+ pn2 = pn1;
+ }
+
+ /* Beware 'for (arguments in ...)' with or without a 'var'. */
+ if (pn2->pn_type == TOK_NAME &&
+ pn2->pn_atom == cx->runtime->atomState.argumentsAtom) {
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ }
+
+ /* Parse the object expression as the right operand of 'in'. */
+ pn2 = NewBinary(cx, TOK_IN, JSOP_NOP, pn1, Expr(cx, ts, tc), tc);
+ if (!pn2)
+ return NULL;
+ pn->pn_left = pn2;
+ } else {
+ /* Parse the loop condition or null into pn2. */
+ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
+ if (js_PeekToken(cx, ts) == TOK_SEMI) {
+ pn2 = NULL;
+ } else {
+ pn2 = Expr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ }
+
+ /* Parse the update expression or null into pn3. */
+ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
+ if (js_PeekToken(cx, ts) == TOK_RP) {
+ pn3 = NULL;
+ } else {
+ pn3 = Expr(cx, ts, tc);
+ if (!pn3)
+ return NULL;
+ }
+
+ /* Build the RESERVED node to use as the left kid of pn. */
+ pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+ if (!pn4)
+ return NULL;
+ pn4->pn_type = TOK_RESERVED;
+ pn4->pn_op = JSOP_NOP;
+ pn4->pn_kid1 = pn1;
+ pn4->pn_kid2 = pn2;
+ pn4->pn_kid3 = pn3;
+ pn->pn_left = pn4;
+ }
+
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
+
+ /* Parse the loop body into pn->pn_right. */
+ pn2 = Statement(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ pn->pn_right = pn2;
+ js_PopStatement(tc);
+
+ /* Record the absolute line number for source note emission. */
+ pn->pn_pos.end = pn2->pn_pos.end;
+ return pn;
+
+#if JS_HAS_EXCEPTIONS
+ case TOK_TRY: {
+ JSParseNode *catchtail = NULL;
+ /*
+ * try nodes are ternary.
+ * kid1 is the try Statement
+ * kid2 is the catch node
+ * kid3 is the finally Statement
+ *
+ * catch nodes are ternary.
+ * kid1 is the discriminant
+ * kid2 is the next catch node, or NULL
+ * kid3 is the catch block (on kid3 so that we can always append a
+ * new catch pn on catchtail->kid2)
+ *
+ * catch discriminant nodes are binary
+ * atom is the receptacle
+ * expr is the discriminant code
+ *
+ * finally nodes are unary (just the finally expression)
+ */
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+ pn->pn_op = JSOP_NOP;
+
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
+ js_PushStatement(tc, &stmtInfo, STMT_TRY, -1);
+ pn->pn_kid1 = Statements(cx, ts, tc);
+ if (!pn->pn_kid1)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
+ js_PopStatement(tc);
+
+ catchtail = pn;
+ while (js_PeekToken(cx, ts) == TOK_CATCH) {
+ /* check for another catch after unconditional catch */
+ if (catchtail != pn && !catchtail->pn_kid1->pn_expr) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_CATCH_AFTER_GENERAL);
+ return NULL;
+ }
+
+ /*
+ * legal catch forms are:
+ * catch (v)
+ * catch (v if <boolean_expression>)
+ * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
+ */
+ (void) js_GetToken(cx, ts); /* eat `catch' */
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+ if (!pn2)
+ return NULL;
+
+ /*
+ * We use a PN_NAME for the discriminant (catchguard) node
+ * with the actual discriminant code in the initializer spot
+ */
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER);
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+ if (!pn3)
+ return NULL;
+
+ pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ pn3->pn_expr = NULL;
+#if JS_HAS_CATCH_GUARD
+ /*
+ * We use `catch (x if x === 5)' (not `catch (x : x === 5)') to
+ * avoid conflicting with the JS2/ECMA2 proposed catchguard syntax.
+ */
+ if (js_PeekToken(cx, ts) == TOK_IF) {
+ (void)js_GetToken(cx, ts); /* eat `if' */
+ pn3->pn_expr = Expr(cx, ts, tc);
+ if (!pn3->pn_expr)
+ return NULL;
+ }
+#endif
+ pn2->pn_kid1 = pn3;
+
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
+
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
+ js_PushStatement(tc, &stmtInfo, STMT_CATCH, -1);
+ stmtInfo.label = pn3->pn_atom;
+ pn2->pn_kid3 = Statements(cx, ts, tc);
+ if (!pn2->pn_kid3)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);
+ js_PopStatement(tc);
+
+ catchtail = catchtail->pn_kid2 = pn2;
+ }
+ catchtail->pn_kid2 = NULL;
+
+ if (js_MatchToken(cx, ts, TOK_FINALLY)) {
+ tc->tryCount++;
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
+ js_PushStatement(tc, &stmtInfo, STMT_FINALLY, -1);
+ pn->pn_kid3 = Statements(cx, ts, tc);
+ if (!pn->pn_kid3)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
+ js_PopStatement(tc);
+ } else {
+ pn->pn_kid3 = NULL;
+ }
+ if (!pn->pn_kid2 && !pn->pn_kid3) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_CATCH_OR_FINALLY);
+ return NULL;
+ }
+ tc->tryCount++;
+ return pn;
+ }
+
+ case TOK_THROW:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+ pn2 = Expr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ pn->pn_pos.end = pn2->pn_pos.end;
+ pn->pn_op = JSOP_THROW;
+ pn->pn_kid = pn2;
+ break;
+
+ /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
+ case TOK_CATCH:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_CATCH_WITHOUT_TRY);
+ return NULL;
+
+ case TOK_FINALLY:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_FINALLY_WITHOUT_TRY);
+ return NULL;
+
+#endif /* JS_HAS_EXCEPTIONS */
+
+ case TOK_BREAK:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn)
+ return NULL;
+ if (!MatchLabel(cx, ts, pn))
+ return NULL;
+ stmt = tc->topStmt;
+ label = pn->pn_atom;
+ if (label) {
+ for (; ; stmt = stmt->down) {
+ if (!stmt) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_LABEL_NOT_FOUND);
+ return NULL;
+ }
+ if (stmt->type == STMT_LABEL && stmt->label == label)
+ break;
+ }
+ } else {
+ for (; ; stmt = stmt->down) {
+ if (!stmt) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_TOUGH_BREAK);
+ return NULL;
+ }
+ if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH)
+ break;
+ }
+ }
+ if (label)
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ break;
+
+ case TOK_CONTINUE:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn)
+ return NULL;
+ if (!MatchLabel(cx, ts, pn))
+ return NULL;
+ stmt = tc->topStmt;
+ label = pn->pn_atom;
+ if (label) {
+ for (stmt2 = NULL; ; stmt = stmt->down) {
+ if (!stmt) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_LABEL_NOT_FOUND);
+ return NULL;
+ }
+ if (stmt->type == STMT_LABEL) {
+ if (stmt->label == label) {
+ if (!stmt2 || !STMT_IS_LOOP(stmt2)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_ERROR,
+ JSMSG_BAD_CONTINUE);
+ return NULL;
+ }
+ break;
+ }
+ } else {
+ stmt2 = stmt;
+ }
+ }
+ } else {
+ for (; ; stmt = stmt->down) {
+ if (!stmt) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_CONTINUE);
+ return NULL;
+ }
+ if (STMT_IS_LOOP(stmt))
+ break;
+ }
+ }
+ if (label)
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ break;
+
+ case TOK_WITH:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
+ pn2 = Expr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
+ pn->pn_left = pn2;
+
+ js_PushStatement(tc, &stmtInfo, STMT_WITH, -1);
+ pn2 = Statement(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ js_PopStatement(tc);
+
+ /* Deprecate after parsing, in case of WERROR option. */
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING | JSREPORT_STRICT,
+ JSMSG_DEPRECATED_USAGE,
+ js_with_statement_str)) {
+ return NULL;
+ }
+
+ pn->pn_pos.end = pn2->pn_pos.end;
+ pn->pn_right = pn2;
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ return pn;
+
+ case TOK_VAR:
+ pn = Variables(cx, ts, tc);
+ if (!pn)
+ return NULL;
+
+ /* Tell js_EmitTree to generate a final POP. */
+ pn->pn_extra = JS_TRUE;
+ break;
+
+ case TOK_RETURN:
+ if (!(tc->flags & TCF_IN_FUNCTION)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_RETURN);
+ return NULL;
+ }
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+
+ /* This is ugly, but we don't want to require a semicolon. */
+ ts->flags |= TSF_REGEXP;
+ tt = js_PeekTokenSameLine(cx, ts);
+ ts->flags &= ~TSF_REGEXP;
+ if (tt == TOK_ERROR)
+ return NULL;
+
+ if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
+ pn2 = Expr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ tc->flags |= TCF_RETURN_EXPR;
+ pn->pn_pos.end = pn2->pn_pos.end;
+ pn->pn_kid = pn2;
+ } else {
+ tc->flags |= TCF_RETURN_VOID;
+ pn->pn_kid = NULL;
+ }
+
+ if (JS_HAS_STRICT_OPTION(cx) &&
+ (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0) {
+ /*
+ * We must be in a frame with a non-native function, because
+ * we're compiling one.
+ */
+ if (!ReportNoReturnValue(cx, ts))
+ return NULL;
+ }
+ break;
+
+ case TOK_LC:
+ js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
+ pn = Statements(cx, ts, tc);
+ if (!pn)
+ return NULL;
+
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
+ js_PopStatement(tc);
+ return pn;
+
+ case TOK_EOL:
+ case TOK_SEMI:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = TOK_SEMI;
+ pn->pn_kid = NULL;
+ return pn;
+
+#if JS_HAS_DEBUGGER_KEYWORD
+ case TOK_DEBUGGER:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = TOK_DEBUGGER;
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ break;
+#endif /* JS_HAS_DEBUGGER_KEYWORD */
+
+ case TOK_ERROR:
+ return NULL;
+
+ default:
+ js_UngetToken(ts);
+ pn2 = Expr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+
+ if (js_PeekToken(cx, ts) == TOK_COLON) {
+ if (pn2->pn_type != TOK_NAME) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_LABEL);
+ return NULL;
+ }
+ label = pn2->pn_atom;
+ for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
+ if (stmt->type == STMT_LABEL && stmt->label == label) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_DUPLICATE_LABEL);
+ return NULL;
+ }
+ }
+ (void) js_GetToken(cx, ts);
+
+ /* Push a label struct and parse the statement. */
+ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
+ stmtInfo.label = label;
+ pn = Statement(cx, ts, tc);
+ if (!pn)
+ return NULL;
+
+ /* Pop the label, set pn_expr, and return early. */
+ js_PopStatement(tc);
+ pn2->pn_type = TOK_COLON;
+ pn2->pn_pos.end = pn->pn_pos.end;
+ pn2->pn_expr = pn;
+ return pn2;
+ }
+
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = TOK_SEMI;
+ pn->pn_pos = pn2->pn_pos;
+ pn->pn_kid = pn2;
+ break;
+ }
+
+ /* Check termination of this primitive statement. */
+ if (ON_CURRENT_LINE(ts, pn->pn_pos)) {
+ tt = js_PeekTokenSameLine(cx, ts);
+ if (tt == TOK_ERROR)
+ return NULL;
+ if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_SEMI_BEFORE_STMNT);
+ return NULL;
+ }
+ }
+
+ (void) js_MatchToken(cx, ts, TOK_SEMI);
+ return pn;
+}
+
+static JSParseNode *
+Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn2;
+ JSObject *obj, *pobj;
+ JSStackFrame *fp;
+ JSFunction *fun;
+ JSClass *clasp;
+ JSPropertyOp getter, setter, currentGetter, currentSetter;
+ JSAtom *atom;
+ JSAtomListElement *ale;
+ JSOp prevop;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+ JSBool ok;
+
+ /*
+ * The tricky part of this code is to create special parsenode opcodes for
+ * getting and setting variables (which will be stored as special slots in
+ * the frame). The complex special case is an eval() inside a function.
+ * If the evaluated string references variables in the enclosing function,
+ * then we need to generate the special variable opcodes. We determine
+ * this by looking up the variable id in the current variable scope.
+ */
+ JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_VAR);
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
+ pn->pn_extra = JS_FALSE; /* assume no JSOP_POP needed */
+ PN_INIT_LIST(pn);
+
+ /*
+ * Skip eval and debugger frames when looking for the function whose code
+ * is being compiled. If we are called from FunctionBody, TCF_IN_FUNCTION
+ * will be set in tc->flags, and we can be sure fp->fun is the function to
+ * use. But if a function calls eval, the string argument is treated as a
+ * Program (per ECMA), so TCF_IN_FUNCTION won't be set.
+ *
+ * What's more, when the following code is reached from eval, cx->fp->fun
+ * is eval's JSFunction (a native function), so we need to skip its frame.
+ * We should find the scripted caller's function frame just below it, but
+ * we code a loop out of paranoia.
+ */
+ for (fp = cx->fp; (fp->flags & JSFRAME_SPECIAL) && fp->down; fp = fp->down)
+ continue;
+ obj = fp->varobj;
+ fun = fp->fun;
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if (fun && clasp == &js_FunctionClass) {
+ /* We are compiling code inside a function */
+ getter = js_GetLocalVariable;
+ setter = js_SetLocalVariable;
+ } else if (fun && clasp == &js_CallClass) {
+ /* We are compiling code from an eval inside a function */
+ getter = js_GetCallVariable;
+ setter = js_SetCallVariable;
+ } else {
+ getter = clasp->getProperty;
+ setter = clasp->setProperty;
+ }
+
+ ok = JS_TRUE;
+ do {
+ currentGetter = getter;
+ currentSetter = setter;
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME);
+ atom = CURRENT_TOKEN(ts).t_atom;
+
+ ATOM_LIST_SEARCH(ale, &tc->decls, atom);
+ if (ale) {
+ prevop = ALE_JSOP(ale);
+ if (JS_HAS_STRICT_OPTION(cx) ||
+ pn->pn_op == JSOP_DEFCONST ||
+ prevop == JSOP_DEFCONST) {
+ const char *name = js_AtomToPrintableString(cx, atom);
+ if (!name ||
+ !js_ReportCompileErrorNumber(cx, ts, NULL,
+ (pn->pn_op != JSOP_DEFCONST &&
+ prevop != JSOP_DEFCONST)
+ ? JSREPORT_WARNING |
+ JSREPORT_STRICT
+ : JSREPORT_ERROR,
+ JSMSG_REDECLARED_VAR,
+ (prevop == JSOP_DEFFUN ||
+ prevop == JSOP_CLOSURE)
+ ? js_function_str
+ : (prevop == JSOP_DEFCONST)
+ ? js_const_str
+ : js_var_str,
+ name)) {
+ return NULL;
+ }
+ }
+ if (pn->pn_op == JSOP_DEFVAR && prevop == JSOP_CLOSURE)
+ tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
+ } else {
+ ale = js_IndexAtom(cx, atom, &tc->decls);
+ if (!ale)
+ return NULL;
+ }
+ ALE_SET_JSOP(ale, pn->pn_op);
+
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+ if (!pn2)
+ return NULL;
+ pn2->pn_op = JSOP_NAME;
+ pn2->pn_atom = atom;
+ pn2->pn_expr = NULL;
+ pn2->pn_slot = -1;
+ pn2->pn_attrs = (pn->pn_op == JSOP_DEFCONST)
+ ? JSPROP_ENUMERATE | JSPROP_PERMANENT |
+ JSPROP_READONLY
+ : JSPROP_ENUMERATE | JSPROP_PERMANENT;
+ PN_APPEND(pn, pn2);
+
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
+ return NULL;
+ if (pobj == obj &&
+ OBJ_IS_NATIVE(pobj) &&
+ (sprop = (JSScopeProperty *)prop) != NULL) {
+ if (sprop->getter == js_GetArgument) {
+ const char *name = js_AtomToPrintableString(cx, atom);
+ if (!name) {
+ ok = JS_FALSE;
+ } else if (pn->pn_op == JSOP_DEFCONST) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_REDECLARED_PARAM,
+ name);
+ ok = JS_FALSE;
+ } else {
+ currentGetter = js_GetArgument;
+ currentSetter = js_SetArgument;
+ ok = js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_VAR_HIDES_ARG,
+ name);
+ }
+ } else {
+ if (fun) {
+ /* Not an argument, must be a redeclared local var. */
+ if (clasp == &js_FunctionClass) {
+ JS_ASSERT(sprop->getter == js_GetLocalVariable);
+ JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
+ sprop->shortid < fun->nvars);
+ } else if (clasp == &js_CallClass) {
+ if (sprop->getter == js_GetCallVariable) {
+ /*
+ * Referencing a variable introduced by a var
+ * statement in the enclosing function. Check
+ * that the slot number we have is in range.
+ */
+ JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
+ sprop->shortid < fun->nvars);
+ } else {
+ /*
+ * A variable introduced through another eval:
+ * don't use the special getters and setters
+ * since we can't allocate a slot in the frame.
+ */
+ currentGetter = sprop->getter;
+ currentSetter = sprop->setter;
+ }
+ }
+
+ /* Override the old getter and setter, to handle eval. */
+ sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,
+ 0, sprop->attrs,
+ currentGetter,
+ currentSetter);
+ if (!sprop)
+ ok = JS_FALSE;
+ }
+ }
+ } else {
+ /*
+ * Property not found in current variable scope: we have not seen
+ * this variable before. Define a new local variable by adding a
+ * property to the function's scope, allocating one slot in the
+ * function's frame. Global variables and any locals declared in
+ * with statement bodies are handled at runtime, by script prolog
+ * JSOP_DEFVAR bytecodes generated for slot-less vars.
+ */
+ sprop = NULL;
+ if (prop) {
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ prop = NULL;
+ }
+ if (currentGetter == js_GetCallVariable) {
+ /* Can't increase fun->nvars in an active frame! */
+ currentGetter = clasp->getProperty;
+ currentSetter = clasp->setProperty;
+ }
+ if (currentGetter == js_GetLocalVariable &&
+ atom != cx->runtime->atomState.argumentsAtom &&
+ fp->scopeChain == obj &&
+ !js_InWithStatement(tc)) {
+ if (!js_AddNativeProperty(cx, obj, (jsid)atom,
+ currentGetter, currentSetter,
+ SPROP_INVALID_SLOT,
+ pn2->pn_attrs | JSPROP_SHARED,
+ SPROP_HAS_SHORTID, fun->nvars)) {
+ ok = JS_FALSE;
+ }
+ fun->nvars++;
+ }
+ }
+
+ if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
+ if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_VAR_INIT);
+ ok = JS_FALSE;
+ } else {
+ pn2->pn_expr = AssignExpr(cx, ts, tc);
+ if (!pn2->pn_expr) {
+ ok = JS_FALSE;
+ } else {
+ pn2->pn_op = (pn->pn_op == JSOP_DEFCONST)
+ ? JSOP_SETCONST
+ : JSOP_SETNAME;
+ if (atom == cx->runtime->atomState.argumentsAtom)
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ }
+ }
+ }
+
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ if (!ok)
+ return NULL;
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
+
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
+ return pn;
+}
+
+static JSParseNode *
+Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn2;
+
+ pn = AssignExpr(cx, ts, tc);
+ if (pn && js_MatchToken(cx, ts, TOK_COMMA)) {
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn2)
+ return NULL;
+ pn2->pn_pos.begin = pn->pn_pos.begin;
+ PN_INIT_LIST_1(pn2, pn);
+ pn = pn2;
+ do {
+ pn2 = AssignExpr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ PN_APPEND(pn, pn2);
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
+ }
+ return pn;
+}
+
+static JSParseNode *
+AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn2;
+ JSTokenType tt;
+ JSOp op;
+
+ CHECK_RECURSION();
+
+ pn = CondExpr(cx, ts, tc);
+ if (!pn)
+ return NULL;
+
+ tt = js_GetToken(cx, ts);
+#if JS_HAS_GETTER_SETTER
+ if (tt == TOK_NAME) {
+ tt = CheckGetterOrSetter(cx, ts, TOK_ASSIGN);
+ if (tt == TOK_ERROR)
+ return NULL;
+ }
+#endif
+ if (tt != TOK_ASSIGN) {
+ js_UngetToken(ts);
+ return pn;
+ }
+
+ op = CURRENT_TOKEN(ts).t_op;
+ for (pn2 = pn; pn2->pn_type == TOK_RP; pn2 = pn2->pn_kid)
+ continue;
+ switch (pn2->pn_type) {
+ case TOK_NAME:
+ pn2->pn_op = JSOP_SETNAME;
+ if (pn2->pn_atom == cx->runtime->atomState.argumentsAtom)
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ break;
+ case TOK_DOT:
+ pn2->pn_op = JSOP_SETPROP;
+ break;
+ case TOK_LB:
+ pn2->pn_op = JSOP_SETELEM;
+ break;
+#if JS_HAS_LVALUE_RETURN
+ case TOK_LP:
+ pn2->pn_op = JSOP_SETCALL;
+ break;
+#endif
+ default:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_LEFTSIDE_OF_ASS);
+ return NULL;
+ }
+ pn = NewBinary(cx, TOK_ASSIGN, op, pn2, AssignExpr(cx, ts, tc), tc);
+ return pn;
+}
+
+static JSParseNode *
+CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn, *pn1, *pn2, *pn3;
+#if JS_HAS_IN_OPERATOR
+ uintN oldflags;
+#endif /* JS_HAS_IN_OPERATOR */
+
+ pn = OrExpr(cx, ts, tc);
+ if (pn && js_MatchToken(cx, ts, TOK_HOOK)) {
+ pn1 = pn;
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+ if (!pn)
+ return NULL;
+#if JS_HAS_IN_OPERATOR
+ /*
+ * Always accept the 'in' operator in the middle clause of a ternary,
+ * where it's unambiguous, even if we might be parsing the init of a
+ * for statement.
+ */
+ oldflags = tc->flags;
+ tc->flags &= ~TCF_IN_FOR_INIT;
+#endif /* JS_HAS_IN_OPERATOR */
+ pn2 = AssignExpr(cx, ts, tc);
+#if JS_HAS_IN_OPERATOR
+ tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
+#endif /* JS_HAS_IN_OPERATOR */
+
+ if (!pn2)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
+ pn3 = AssignExpr(cx, ts, tc);
+ if (!pn3)
+ return NULL;
+ pn->pn_pos.begin = pn1->pn_pos.begin;
+ pn->pn_pos.end = pn3->pn_pos.end;
+ pn->pn_kid1 = pn1;
+ pn->pn_kid2 = pn2;
+ pn->pn_kid3 = pn3;
+ }
+ return pn;
+}
+
+static JSParseNode *
+OrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+
+ pn = AndExpr(cx, ts, tc);
+ if (pn && js_MatchToken(cx, ts, TOK_OR))
+ pn = NewBinary(cx, TOK_OR, JSOP_OR, pn, OrExpr(cx, ts, tc), tc);
+ return pn;
+}
+
+static JSParseNode *
+AndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+
+ pn = BitOrExpr(cx, ts, tc);
+ if (pn && js_MatchToken(cx, ts, TOK_AND))
+ pn = NewBinary(cx, TOK_AND, JSOP_AND, pn, AndExpr(cx, ts, tc), tc);
+ return pn;
+}
+
+static JSParseNode *
+BitOrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+
+ pn = BitXorExpr(cx, ts, tc);
+ while (pn && js_MatchToken(cx, ts, TOK_BITOR)) {
+ pn = NewBinary(cx, TOK_BITOR, JSOP_BITOR, pn, BitXorExpr(cx, ts, tc),
+ tc);
+ }
+ return pn;
+}
+
+static JSParseNode *
+BitXorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+
+ pn = BitAndExpr(cx, ts, tc);
+ while (pn && js_MatchToken(cx, ts, TOK_BITXOR)) {
+ pn = NewBinary(cx, TOK_BITXOR, JSOP_BITXOR, pn, BitAndExpr(cx, ts, tc),
+ tc);
+ }
+ return pn;
+}
+
+static JSParseNode *
+BitAndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+
+ pn = EqExpr(cx, ts, tc);
+ while (pn && js_MatchToken(cx, ts, TOK_BITAND))
+ pn = NewBinary(cx, TOK_BITAND, JSOP_BITAND, pn, EqExpr(cx, ts, tc), tc);
+ return pn;
+}
+
+static JSParseNode *
+EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+ JSOp op;
+
+ pn = RelExpr(cx, ts, tc);
+ while (pn && js_MatchToken(cx, ts, TOK_EQOP)) {
+ op = CURRENT_TOKEN(ts).t_op;
+ pn = NewBinary(cx, TOK_EQOP, op, pn, RelExpr(cx, ts, tc), tc);
+ }
+ return pn;
+}
+
+static JSParseNode *
+RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+ JSTokenType tt;
+ JSOp op;
+#if JS_HAS_IN_OPERATOR
+ uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT;
+
+ /*
+ * Uses of the in operator in ShiftExprs are always unambiguous,
+ * so unset the flag that prohibits recognizing it.
+ */
+ tc->flags &= ~TCF_IN_FOR_INIT;
+#endif /* JS_HAS_IN_OPERATOR */
+
+ pn = ShiftExpr(cx, ts, tc);
+ while (pn &&
+ (js_MatchToken(cx, ts, TOK_RELOP)
+#if JS_HAS_IN_OPERATOR
+ /*
+ * Recognize the 'in' token as an operator only if we're not
+ * currently in the init expr of a for loop.
+ */
+ || (inForInitFlag == 0 && js_MatchToken(cx, ts, TOK_IN))
+#endif /* JS_HAS_IN_OPERATOR */
+#if JS_HAS_INSTANCEOF
+ || js_MatchToken(cx, ts, TOK_INSTANCEOF)
+#endif /* JS_HAS_INSTANCEOF */
+ )) {
+ tt = CURRENT_TOKEN(ts).type;
+ op = CURRENT_TOKEN(ts).t_op;
+ pn = NewBinary(cx, tt, op, pn, ShiftExpr(cx, ts, tc), tc);
+ }
+#if JS_HAS_IN_OPERATOR
+ /* Restore previous state of inForInit flag. */
+ tc->flags |= inForInitFlag;
+#endif /* JS_HAS_IN_OPERATOR */
+
+ return pn;
+}
+
+static JSParseNode *
+ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+ JSOp op;
+
+ pn = AddExpr(cx, ts, tc);
+ while (pn && js_MatchToken(cx, ts, TOK_SHOP)) {
+ op = CURRENT_TOKEN(ts).t_op;
+ pn = NewBinary(cx, TOK_SHOP, op, pn, AddExpr(cx, ts, tc), tc);
+ }
+ return pn;
+}
+
+static JSParseNode *
+AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+ JSTokenType tt;
+ JSOp op;
+
+ pn = MulExpr(cx, ts, tc);
+ while (pn &&
+ (js_MatchToken(cx, ts, TOK_PLUS) ||
+ js_MatchToken(cx, ts, TOK_MINUS))) {
+ tt = CURRENT_TOKEN(ts).type;
+ op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB;
+ pn = NewBinary(cx, tt, op, pn, MulExpr(cx, ts, tc), tc);
+ }
+ return pn;
+}
+
+static JSParseNode *
+MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSParseNode *pn;
+ JSTokenType tt;
+ JSOp op;
+
+ pn = UnaryExpr(cx, ts, tc);
+ while (pn &&
+ (js_MatchToken(cx, ts, TOK_STAR) ||
+ js_MatchToken(cx, ts, TOK_DIVOP))) {
+ tt = CURRENT_TOKEN(ts).type;
+ op = CURRENT_TOKEN(ts).t_op;
+ pn = NewBinary(cx, tt, op, pn, UnaryExpr(cx, ts, tc), tc);
+ }
+ return pn;
+}
+
+static JSParseNode *
+SetLvalKid(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, JSParseNode *kid,
+ const char *name)
+{
+ while (kid->pn_type == TOK_RP)
+ kid = kid->pn_kid;
+ if (kid->pn_type != TOK_NAME &&
+ kid->pn_type != TOK_DOT &&
+#if JS_HAS_LVALUE_RETURN
+ (kid->pn_type != TOK_LP || kid->pn_op != JSOP_CALL) &&
+#endif
+ kid->pn_type != TOK_LB) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_OPERAND, name);
+ return NULL;
+ }
+ pn->pn_kid = kid;
+ return kid;
+}
+
+static const char *incop_name_str[] = {"increment", "decrement"};
+
+static JSBool
+SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
+ JSParseNode *pn, JSParseNode *kid,
+ JSTokenType tt, JSBool preorder)
+{
+ JSOp op;
+
+ kid = SetLvalKid(cx, ts, pn, kid, incop_name_str[tt == TOK_DEC]);
+ if (!kid)
+ return JS_FALSE;
+ switch (kid->pn_type) {
+ case TOK_NAME:
+ op = (tt == TOK_INC)
+ ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
+ : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
+ if (kid->pn_atom == cx->runtime->atomState.argumentsAtom)
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ break;
+
+ case TOK_DOT:
+ op = (tt == TOK_INC)
+ ? (preorder ? JSOP_INCPROP : JSOP_PROPINC)
+ : (preorder ? JSOP_DECPROP : JSOP_PROPDEC);
+ break;
+
+#if JS_HAS_LVALUE_RETURN
+ case TOK_LP:
+ kid->pn_op = JSOP_SETCALL;
+#endif
+ case TOK_LB:
+ op = (tt == TOK_INC)
+ ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC)
+ : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC);
+ break;
+
+ default:
+ JS_ASSERT(0);
+ op = JSOP_NOP;
+ }
+ pn->pn_op = op;
+ return JS_TRUE;
+}
+
+static JSParseNode *
+UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSTokenType tt;
+ JSParseNode *pn, *pn2;
+
+ ts->flags |= TSF_REGEXP;
+ tt = js_GetToken(cx, ts);
+ ts->flags &= ~TSF_REGEXP;
+
+ switch (tt) {
+ case TOK_UNARYOP:
+ case TOK_PLUS:
+ case TOK_MINUS:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = TOK_UNARYOP; /* PLUS and MINUS are binary */
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
+ pn2 = UnaryExpr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ pn->pn_pos.end = pn2->pn_pos.end;
+ pn->pn_kid = pn2;
+ break;
+
+ case TOK_INC:
+ case TOK_DEC:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+ pn2 = MemberExpr(cx, ts, tc, JS_TRUE);
+ if (!pn2)
+ return NULL;
+ if (!SetIncOpKid(cx, ts, tc, pn, pn2, tt, JS_TRUE))
+ return NULL;
+ pn->pn_pos.end = pn2->pn_pos.end;
+ break;
+
+ case TOK_DELETE:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+ pn2 = UnaryExpr(cx, ts, tc);
+ if (!pn2)
+ return NULL;
+ pn->pn_pos.end = pn2->pn_pos.end;
+
+ /*
+ * Under ECMA3, deleting any unary expression is valid -- it simply
+ * returns true. Here we strip off any parentheses.
+ */
+ while (pn2->pn_type == TOK_RP)
+ pn2 = pn2->pn_kid;
+ pn->pn_kid = pn2;
+ break;
+
+ case TOK_ERROR:
+ return NULL;
+
+ default:
+ js_UngetToken(ts);
+ pn = MemberExpr(cx, ts, tc, JS_TRUE);
+ if (!pn)
+ return NULL;
+
+ /* Don't look across a newline boundary for a postfix incop. */
+ if (ON_CURRENT_LINE(ts, pn->pn_pos)) {
+ tt = js_PeekTokenSameLine(cx, ts);
+ if (tt == TOK_INC || tt == TOK_DEC) {
+ (void) js_GetToken(cx, ts);
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn2)
+ return NULL;
+ if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE))
+ return NULL;
+ pn2->pn_pos.begin = pn->pn_pos.begin;
+ pn = pn2;
+ }
+ }
+ break;
+ }
+ return pn;
+}
+
+static JSBool
+ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
+ JSParseNode *listNode)
+{
+ JSBool matched;
+
+ ts->flags |= TSF_REGEXP;
+ matched = js_MatchToken(cx, ts, TOK_RP);
+ ts->flags &= ~TSF_REGEXP;
+ if (!matched) {
+ do {
+ JSParseNode *argNode = AssignExpr(cx, ts, tc);
+ if (!argNode)
+ return JS_FALSE;
+ PN_APPEND(listNode, argNode);
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
+
+ if (js_GetToken(cx, ts) != TOK_RP) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_PAREN_AFTER_ARGS);
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSParseNode *
+MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
+ JSBool allowCallSyntax)
+{
+ JSParseNode *pn, *pn2, *pn3;
+ JSTokenType tt;
+
+ CHECK_RECURSION();
+
+ /* Check for new expression first. */
+ ts->flags |= TSF_REGEXP;
+ tt = js_PeekToken(cx, ts);
+ ts->flags &= ~TSF_REGEXP;
+ if (tt == TOK_NEW) {
+ (void) js_GetToken(cx, ts);
+
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn)
+ return NULL;
+ pn2 = MemberExpr(cx, ts, tc, JS_FALSE);
+ if (!pn2)
+ return NULL;
+ pn->pn_op = JSOP_NEW;
+ PN_INIT_LIST_1(pn, pn2);
+ pn->pn_pos.begin = pn2->pn_pos.begin;
+
+ if (js_MatchToken(cx, ts, TOK_LP) && !ArgumentList(cx, ts, tc, pn))
+ return NULL;
+ if (pn->pn_count > ARGC_LIMIT) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_TOO_MANY_CON_ARGS);
+ return NULL;
+ }
+ pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;
+ } else {
+ pn = PrimaryExpr(cx, ts, tc);
+ if (!pn)
+ return NULL;
+ }
+
+ while ((tt = js_GetToken(cx, ts)) > TOK_EOF) {
+ if (tt == TOK_DOT) {
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+ if (!pn2)
+ return NULL;
+ MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
+ pn2->pn_pos.begin = pn->pn_pos.begin;
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ pn2->pn_op = JSOP_GETPROP;
+ pn2->pn_expr = pn;
+ pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ } else if (tt == TOK_LB) {
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+ if (!pn2)
+ return NULL;
+ pn3 = Expr(cx, ts, tc);
+ if (!pn3)
+ return NULL;
+
+ MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
+ pn2->pn_pos.begin = pn->pn_pos.begin;
+ pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+
+ /* Optimize o['p'] to o.p by rewriting pn2. */
+ if (pn3->pn_type == TOK_STRING) {
+ pn2->pn_type = TOK_DOT;
+ pn2->pn_op = JSOP_GETPROP;
+ pn2->pn_arity = PN_NAME;
+ pn2->pn_expr = pn;
+ pn2->pn_atom = pn3->pn_atom;
+ } else {
+ pn2->pn_op = JSOP_GETELEM;
+ pn2->pn_left = pn;
+ pn2->pn_right = pn3;
+ }
+ } else if (allowCallSyntax && tt == TOK_LP) {
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn2)
+ return NULL;
+
+ /* Pick JSOP_EVAL and flag tc as heavyweight if eval(...). */
+ pn2->pn_op = JSOP_CALL;
+ if (pn->pn_op == JSOP_NAME &&
+ pn->pn_atom == cx->runtime->atomState.evalAtom) {
+ pn2->pn_op = JSOP_EVAL;
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ }
+
+ PN_INIT_LIST_1(pn2, pn);
+ pn2->pn_pos.begin = pn->pn_pos.begin;
+
+ if (!ArgumentList(cx, ts, tc, pn2))
+ return NULL;
+ if (pn2->pn_count > ARGC_LIMIT) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_TOO_MANY_FUN_ARGS);
+ return NULL;
+ }
+ pn2->pn_pos.end = PN_LAST(pn2)->pn_pos.end;
+ } else {
+ js_UngetToken(ts);
+ return pn;
+ }
+
+ pn = pn2;
+ }
+ if (tt == TOK_ERROR)
+ return NULL;
+ return pn;
+}
+
+static JSParseNode *
+PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+ JSTokenType tt;
+ JSParseNode *pn, *pn2, *pn3;
+ char *badWord;
+#if JS_HAS_GETTER_SETTER
+ JSAtom *atom;
+ JSRuntime *rt;
+#endif
+
+#if JS_HAS_SHARP_VARS
+ JSParseNode *defsharp;
+ JSBool notsharp;
+
+ defsharp = NULL;
+ notsharp = JS_FALSE;
+ again:
+ /*
+ * Control flows here after #n= is scanned. If the following primary is
+ * not valid after such a "sharp variable" definition, the token type case
+ * should set notsharp.
+ */
+#endif
+
+ CHECK_RECURSION();
+
+ ts->flags |= TSF_REGEXP;
+ tt = js_GetToken(cx, ts);
+ ts->flags &= ~TSF_REGEXP;
+
+#if JS_HAS_GETTER_SETTER
+ if (tt == TOK_NAME) {
+ tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);
+ if (tt == TOK_ERROR)
+ return NULL;
+ }
+#endif
+
+ switch (tt) {
+#if JS_HAS_LEXICAL_CLOSURE
+ case TOK_FUNCTION:
+ pn = FunctionExpr(cx, ts, tc);
+ if (!pn)
+ return NULL;
+ break;
+#endif
+
+#if JS_HAS_INITIALIZERS
+ case TOK_LB:
+ {
+ JSBool matched;
+ jsuint atomIndex;
+
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = TOK_RB;
+ pn->pn_extra = JS_FALSE;
+
+#if JS_HAS_SHARP_VARS
+ if (defsharp) {
+ PN_INIT_LIST_1(pn, defsharp);
+ defsharp = NULL;
+ } else
+#endif
+ PN_INIT_LIST(pn);
+
+ ts->flags |= TSF_REGEXP;
+ matched = js_MatchToken(cx, ts, TOK_RB);
+ ts->flags &= ~TSF_REGEXP;
+ if (!matched) {
+ for (atomIndex = 0; atomIndex < ATOM_INDEX_LIMIT; atomIndex++) {
+ ts->flags |= TSF_REGEXP;
+ tt = js_PeekToken(cx, ts);
+ ts->flags &= ~TSF_REGEXP;
+ if (tt == TOK_RB) {
+ pn->pn_extra = JS_TRUE;
+ break;
+ }
+
+ if (tt == TOK_COMMA) {
+ /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */
+ js_MatchToken(cx, ts, TOK_COMMA);
+ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ } else {
+ pn2 = AssignExpr(cx, ts, tc);
+ }
+ if (!pn2)
+ return NULL;
+ PN_APPEND(pn, pn2);
+
+ if (tt != TOK_COMMA) {
+ /* If we didn't already match TOK_COMMA in above case. */
+ if (!js_MatchToken(cx, ts, TOK_COMMA))
+ break;
+ }
+ }
+
+ MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
+ }
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ return pn;
+ }
+
+ case TOK_LC:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_type = TOK_RC;
+
+#if JS_HAS_SHARP_VARS
+ if (defsharp) {
+ PN_INIT_LIST_1(pn, defsharp);
+ defsharp = NULL;
+ } else
+#endif
+ PN_INIT_LIST(pn);
+
+ if (!js_MatchToken(cx, ts, TOK_RC)) {
+ do {
+ JSOp op;
+
+ tt = js_GetToken(cx, ts);
+ switch (tt) {
+ case TOK_NUMBER:
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (pn3)
+ pn3->pn_dval = CURRENT_TOKEN(ts).t_dval;
+ break;
+ case TOK_NAME:
+#if JS_HAS_GETTER_SETTER
+ atom = CURRENT_TOKEN(ts).t_atom;
+ rt = cx->runtime;
+ if (atom == rt->atomState.getAtom ||
+ atom == rt->atomState.setAtom) {
+ op = (atom == rt->atomState.getAtom)
+ ? JSOP_GETTER
+ : JSOP_SETTER;
+ if (js_MatchToken(cx, ts, TOK_NAME)) {
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME,
+ tc);
+ if (!pn3)
+ return NULL;
+ pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ pn3->pn_expr = NULL;
+
+ /* We have to fake a 'function' token here. */
+ CURRENT_TOKEN(ts).t_op = JSOP_NOP;
+ CURRENT_TOKEN(ts).type = TOK_FUNCTION;
+ pn2 = FunctionExpr(cx, ts, tc);
+ pn2 = NewBinary(cx, TOK_COLON, op, pn3, pn2, tc);
+ goto skip;
+ }
+ }
+ /* else fall thru ... */
+#endif
+ case TOK_STRING:
+ pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (pn3)
+ pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ break;
+ case TOK_RC:
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_TRAILING_COMMA)) {
+ return NULL;
+ }
+ goto end_obj_init;
+ default:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_PROP_ID);
+ return NULL;
+ }
+
+ tt = js_GetToken(cx, ts);
+#if JS_HAS_GETTER_SETTER
+ if (tt == TOK_NAME) {
+ tt = CheckGetterOrSetter(cx, ts, TOK_COLON);
+ if (tt == TOK_ERROR)
+ return NULL;
+ }
+#endif
+ if (tt != TOK_COLON) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_COLON_AFTER_ID);
+ return NULL;
+ }
+ op = CURRENT_TOKEN(ts).t_op;
+ pn2 = NewBinary(cx, TOK_COLON, op, pn3, AssignExpr(cx, ts, tc),
+ tc);
+#if JS_HAS_GETTER_SETTER
+ skip:
+#endif
+ if (!pn2)
+ return NULL;
+ PN_APPEND(pn, pn2);
+ } while (js_MatchToken(cx, ts, TOK_COMMA));
+
+ MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LIST);
+ }
+ end_obj_init:
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ return pn;
+
+#if JS_HAS_SHARP_VARS
+ case TOK_DEFSHARP:
+ if (defsharp)
+ goto badsharp;
+ defsharp = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!defsharp)
+ return NULL;
+ defsharp->pn_kid = NULL;
+ defsharp->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
+ goto again;
+
+ case TOK_USESHARP:
+ /* Check for forward/dangling references at runtime, to allow eval. */
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
+ notsharp = JS_TRUE;
+ break;
+#endif /* JS_HAS_SHARP_VARS */
+#endif /* JS_HAS_INITIALIZERS */
+
+ case TOK_LP:
+ {
+#if JS_HAS_IN_OPERATOR
+ uintN oldflags;
+#endif
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ if (!pn)
+ return NULL;
+#if JS_HAS_IN_OPERATOR
+ /*
+ * Always accept the 'in' operator in a parenthesized expression,
+ * where it's unambiguous, even if we might be parsing the init of a
+ * for statement.
+ */
+ oldflags = tc->flags;
+ tc->flags &= ~TCF_IN_FOR_INIT;
+#endif
+ pn2 = Expr(cx, ts, tc);
+#if JS_HAS_IN_OPERATOR
+ tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
+#endif
+ if (!pn2)
+ return NULL;
+
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
+ pn->pn_type = TOK_RP;
+ pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
+ pn->pn_kid = pn2;
+ break;
+ }
+
+ case TOK_STRING:
+#if JS_HAS_SHARP_VARS
+ notsharp = JS_TRUE;
+#endif
+ /* FALL THROUGH */
+ case TOK_NAME:
+ case TOK_OBJECT:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
+ pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
+ if (tt == TOK_NAME) {
+ pn->pn_arity = PN_NAME;
+ pn->pn_expr = NULL;
+ pn->pn_slot = -1;
+ pn->pn_attrs = 0;
+
+ /* Unqualified __parent__ and __proto__ uses require activations. */
+ if (pn->pn_atom == cx->runtime->atomState.parentAtom ||
+ pn->pn_atom == cx->runtime->atomState.protoAtom) {
+ tc->flags |= TCF_FUN_HEAVYWEIGHT;
+ }
+ }
+ break;
+
+ case TOK_NUMBER:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_dval = CURRENT_TOKEN(ts).t_dval;
+#if JS_HAS_SHARP_VARS
+ notsharp = JS_TRUE;
+#endif
+ break;
+
+ case TOK_PRIMARY:
+ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+ if (!pn)
+ return NULL;
+ pn->pn_op = CURRENT_TOKEN(ts).t_op;
+#if JS_HAS_SHARP_VARS
+ notsharp = JS_TRUE;
+#endif
+ break;
+
+#if !JS_HAS_EXPORT_IMPORT
+ case TOK_EXPORT:
+ case TOK_IMPORT:
+#endif
+ case TOK_RESERVED:
+ badWord = js_DeflateString(cx, CURRENT_TOKEN(ts).ptr,
+ (size_t) CURRENT_TOKEN(ts).pos.end.index
+ - CURRENT_TOKEN(ts).pos.begin.index);
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_RESERVED_ID, badWord);
+ JS_free(cx, badWord);
+ return NULL;
+
+ case TOK_ERROR:
+ /* The scanner or one of its subroutines reported the error. */
+ return NULL;
+
+ default:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_SYNTAX_ERROR);
+ return NULL;
+ }
+
+#if JS_HAS_SHARP_VARS
+ if (defsharp) {
+ if (notsharp) {
+ badsharp:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_SHARP_VAR_DEF);
+ return NULL;
+ }
+ defsharp->pn_kid = pn;
+ return defsharp;
+ }
+#endif
+ return pn;
+}
+
+static JSBool
+ContainsVarStmt(JSParseNode *pn)
+{
+ JSParseNode *pn2;
+
+ if (!pn)
+ return JS_FALSE;
+ switch (pn->pn_arity) {
+ case PN_LIST:
+ if (pn->pn_type == TOK_VAR)
+ return JS_TRUE;
+ for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
+ if (ContainsVarStmt(pn2))
+ return JS_TRUE;
+ }
+ break;
+ case PN_TERNARY:
+ return ContainsVarStmt(pn->pn_kid1) ||
+ ContainsVarStmt(pn->pn_kid2) ||
+ ContainsVarStmt(pn->pn_kid3);
+ case PN_BINARY:
+ /*
+ * Limit recursion if pn is a binary expression, which can't contain a
+ * var statement.
+ */
+ if (pn->pn_op != JSOP_NOP)
+ return JS_FALSE;
+ return ContainsVarStmt(pn->pn_left) || ContainsVarStmt(pn->pn_right);
+ case PN_UNARY:
+ if (pn->pn_op != JSOP_NOP)
+ return JS_FALSE;
+ return ContainsVarStmt(pn->pn_kid);
+ default:;
+ }
+ return JS_FALSE;
+}
+
+/*
+ * Fold from one constant type to another.
+ * XXX handles only strings and numbers for now
+ */
+static JSBool
+FoldType(JSContext *cx, JSParseNode *pn, JSTokenType type)
+{
+ if (pn->pn_type != type) {
+ switch (type) {
+ case TOK_NUMBER:
+ if (pn->pn_type == TOK_STRING) {
+ jsdouble d;
+ if (!js_ValueToNumber(cx, ATOM_KEY(pn->pn_atom), &d))
+ return JS_FALSE;
+ pn->pn_dval = d;
+ pn->pn_type = TOK_NUMBER;
+ pn->pn_op = JSOP_NUMBER;
+ }
+ break;
+
+ case TOK_STRING:
+ if (pn->pn_type == TOK_NUMBER) {
+ JSString *str = js_NumberToString(cx, pn->pn_dval);
+ if (!str)
+ return JS_FALSE;
+ pn->pn_atom = js_AtomizeString(cx, str, 0);
+ if (!pn->pn_atom)
+ return JS_FALSE;
+ pn->pn_type = TOK_STRING;
+ pn->pn_op = JSOP_STRING;
+ }
+ break;
+
+ default:;
+ }
+ }
+ return JS_TRUE;
+}
+
+/*
+ * Fold two numeric constants. Beware that pn1 and pn2 are recycled, unless
+ * one of them aliases pn, so you can't safely fetch pn2->pn_next, e.g., after
+ * a successful call to this function.
+ */
+static JSBool
+FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
+ JSParseNode *pn, JSTreeContext *tc)
+{
+ jsdouble d, d2;
+ int32 i, j;
+ uint32 u;
+
+ JS_ASSERT(pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER);
+ d = pn1->pn_dval;
+ d2 = pn2->pn_dval;
+ switch (op) {
+ case JSOP_LSH:
+ case JSOP_RSH:
+ if (!js_DoubleToECMAInt32(cx, d, &i))
+ return JS_FALSE;
+ if (!js_DoubleToECMAInt32(cx, d2, &j))
+ return JS_FALSE;
+ j &= 31;
+ d = (op == JSOP_LSH) ? i << j : i >> j;
+ break;
+
+ case JSOP_URSH:
+ if (!js_DoubleToECMAUint32(cx, d, &u))
+ return JS_FALSE;
+ if (!js_DoubleToECMAInt32(cx, d2, &j))
+ return JS_FALSE;
+ j &= 31;
+ d = u >> j;
+ break;
+
+ case JSOP_ADD:
+ d += d2;
+ break;
+
+ case JSOP_SUB:
+ d -= d2;
+ break;
+
+ case JSOP_MUL:
+ d *= d2;
+ break;
+
+ case JSOP_DIV:
+ if (d2 == 0) {
+#if defined(XP_WIN)
+ /* XXX MSVC miscompiles such that (NaN == 0) */
+ if (JSDOUBLE_IS_NaN(d2))
+ d = *cx->runtime->jsNaN;
+ else
+#endif
+ if (d == 0 || JSDOUBLE_IS_NaN(d))
+ d = *cx->runtime->jsNaN;
+ else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31)
+ d = *cx->runtime->jsNegativeInfinity;
+ else
+ d = *cx->runtime->jsPositiveInfinity;
+ } else {
+ d /= d2;
+ }
+ break;
+
+ case JSOP_MOD:
+ if (d2 == 0) {
+ d = *cx->runtime->jsNaN;
+ } else {
+#if defined(XP_WIN)
+ /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
+ if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
+#endif
+ d = fmod(d, d2);
+ }
+ break;
+
+ default:;
+ }
+
+ /* Take care to allow pn1 or pn2 to alias pn. */
+ if (pn1 != pn)
+ RecycleTree(pn1, tc);
+ if (pn2 != pn)
+ RecycleTree(pn2, tc);
+ pn->pn_type = TOK_NUMBER;
+ pn->pn_op = JSOP_NUMBER;
+ pn->pn_arity = PN_NULLARY;
+ pn->pn_dval = d;
+ return JS_TRUE;
+}
+
+JSBool
+js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
+{
+ JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
+ int stackDummy;
+
+ if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
+ return JS_FALSE;
+ }
+
+ switch (pn->pn_arity) {
+ case PN_FUNC:
+ if (!js_FoldConstants(cx, pn->pn_body, tc))
+ return JS_FALSE;
+ break;
+
+ case PN_LIST:
+ /* Save the list head in pn1 for later use. */
+ for (pn1 = pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
+ if (!js_FoldConstants(cx, pn2, tc))
+ return JS_FALSE;
+ }
+ break;
+
+ case PN_TERNARY:
+ /* Any kid may be null (e.g. for (;;)). */
+ pn1 = pn->pn_kid1;
+ pn2 = pn->pn_kid2;
+ pn3 = pn->pn_kid3;
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
+ return JS_FALSE;
+ if (pn2 && !js_FoldConstants(cx, pn2, tc))
+ return JS_FALSE;
+ if (pn3 && !js_FoldConstants(cx, pn3, tc))
+ return JS_FALSE;
+ break;
+
+ case PN_BINARY:
+ /* First kid may be null (for default case in switch). */
+ pn1 = pn->pn_left;
+ pn2 = pn->pn_right;
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
+ return JS_FALSE;
+ if (!js_FoldConstants(cx, pn2, tc))
+ return JS_FALSE;
+ break;
+
+ case PN_UNARY:
+ /* Our kid may be null (e.g. return; vs. return e;). */
+ pn1 = pn->pn_kid;
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
+ return JS_FALSE;
+ break;
+
+ case PN_NAME:
+ /*
+ * Skip pn1 down along a chain of dotted member expressions to avoid
+ * excessive recursion. Our only goal here is to fold constants (if
+ * any) in the primary expression operand to the left of the first
+ * dot in the chain.
+ */
+ pn1 = pn->pn_expr;
+ while (pn1 && pn1->pn_arity == PN_NAME)
+ pn1 = pn1->pn_expr;
+ if (pn1 && !js_FoldConstants(cx, pn1, tc))
+ return JS_FALSE;
+ break;
+
+ case PN_NULLARY:
+ break;
+ }
+
+ switch (pn->pn_type) {
+ case TOK_IF:
+ if (ContainsVarStmt(pn2) || ContainsVarStmt(pn3))
+ break;
+ /* FALL THROUGH */
+
+ case TOK_HOOK:
+ /* Reduce 'if (C) T; else E' into T for true C, E for false. */
+ switch (pn1->pn_type) {
+ case TOK_NUMBER:
+ if (pn1->pn_dval == 0)
+ pn2 = pn3;
+ break;
+ case TOK_STRING:
+ if (JSSTRING_LENGTH(ATOM_TO_STRING(pn1->pn_atom)) == 0)
+ pn2 = pn3;
+ break;
+ case TOK_PRIMARY:
+ if (pn1->pn_op == JSOP_TRUE)
+ break;
+ if (pn1->pn_op == JSOP_FALSE || pn1->pn_op == JSOP_NULL) {
+ pn2 = pn3;
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ /* Early return to dodge common code that copies pn2 to pn. */
+ return JS_TRUE;
+ }
+
+ if (pn2) {
+ /* pn2 is the then- or else-statement subtree to compile. */
+ PN_MOVE_NODE(pn, pn2);
+ } else {
+ /* False condition and no else: make pn an empty statement. */
+ pn->pn_type = TOK_SEMI;
+ pn->pn_arity = PN_UNARY;
+ pn->pn_kid = NULL;
+ }
+ RecycleTree(pn2, tc);
+ if (pn3 && pn3 != pn2)
+ RecycleTree(pn3, tc);
+ break;
+
+ case TOK_PLUS:
+ if (pn->pn_arity == PN_LIST) {
+ size_t length, length2;
+ jschar *chars;
+ JSString *str, *str2;
+
+ /*
+ * Any string literal term with all others number or string means
+ * this is a concatenation. If any term is not a string or number
+ * literal, we can't fold.
+ */
+ JS_ASSERT(pn->pn_count > 2);
+ if (pn->pn_extra & PNX_CANTFOLD)
+ return JS_TRUE;
+ if (pn->pn_extra != PNX_STRCAT)
+ goto do_binary_op;
+
+ /* Ok, we're concatenating: convert non-string constant operands. */
+ length = 0;
+ for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
+ if (!FoldType(cx, pn2, TOK_STRING))
+ return JS_FALSE;
+ /* XXX fold only if all operands convert to string */
+ if (pn2->pn_type != TOK_STRING)
+ return JS_TRUE;
+ length += ATOM_TO_STRING(pn2->pn_atom)->length;
+ }
+
+ /* Allocate a new buffer and string descriptor for the result. */
+ chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
+ if (!chars)
+ return JS_FALSE;
+ str = js_NewString(cx, chars, length, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+
+ /* Fill the buffer, advancing chars and recycling kids as we go. */
+ for (pn2 = pn1; pn2; pn2 = pn3) {
+ str2 = ATOM_TO_STRING(pn2->pn_atom);
+ length2 = str2->length;
+ js_strncpy(chars, str2->chars, length2);
+ chars += length2;
+ pn3 = pn2->pn_next;
+ RecycleTree(pn2, tc);
+ }
+ *chars = 0;
+
+ /* Atomize the result string and mutate pn to refer to it. */
+ pn->pn_atom = js_AtomizeString(cx, str, 0);
+ if (!pn->pn_atom)
+ return JS_FALSE;
+ pn->pn_type = TOK_STRING;
+ pn->pn_op = JSOP_STRING;
+ pn->pn_arity = PN_NULLARY;
+ break;
+ }
+
+ /* Handle a binary string concatenation. */
+ JS_ASSERT(pn->pn_arity == PN_BINARY);
+ if (pn1->pn_type == TOK_STRING || pn2->pn_type == TOK_STRING) {
+ JSString *left, *right, *str;
+
+ if (!FoldType(cx, (pn1->pn_type != TOK_STRING) ? pn1 : pn2,
+ TOK_STRING)) {
+ return JS_FALSE;
+ }
+ if (pn1->pn_type != TOK_STRING || pn2->pn_type != TOK_STRING)
+ return JS_TRUE;
+ left = ATOM_TO_STRING(pn1->pn_atom);
+ right = ATOM_TO_STRING(pn2->pn_atom);
+ str = js_ConcatStrings(cx, left, right);
+ if (!str)
+ return JS_FALSE;
+ pn->pn_atom = js_AtomizeString(cx, str, 0);
+ if (!pn->pn_atom)
+ return JS_FALSE;
+ pn->pn_type = TOK_STRING;
+ pn->pn_op = JSOP_STRING;
+ pn->pn_arity = PN_NULLARY;
+ RecycleTree(pn1, tc);
+ RecycleTree(pn2, tc);
+ break;
+ }
+
+ /* Can't concatenate string literals, let's try numbers. */
+ goto do_binary_op;
+
+ case TOK_STAR:
+ /* The * in 'import *;' parses as a nullary star node. */
+ if (pn->pn_arity == PN_NULLARY)
+ break;
+ /* FALL THROUGH */
+
+ case TOK_SHOP:
+ case TOK_MINUS:
+ case TOK_DIVOP:
+ do_binary_op:
+ if (pn->pn_arity == PN_LIST) {
+ JS_ASSERT(pn->pn_count > 2);
+ for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
+ if (!FoldType(cx, pn2, TOK_NUMBER))
+ return JS_FALSE;
+ /* XXX fold only if all operands convert to number */
+ if (pn2->pn_type != TOK_NUMBER)
+ break;
+ }
+ if (!pn2) {
+ JSOp op = pn->pn_op;
+
+ pn2 = pn1->pn_next;
+ pn3 = pn2->pn_next;
+ if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, tc))
+ return JS_FALSE;
+ while ((pn2 = pn3) != NULL) {
+ pn3 = pn2->pn_next;
+ if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, tc))
+ return JS_FALSE;
+ }
+ }
+ } else {
+ JS_ASSERT(pn->pn_arity == PN_BINARY);
+ if (!FoldType(cx, pn1, TOK_NUMBER) ||
+ !FoldType(cx, pn2, TOK_NUMBER)) {
+ return JS_FALSE;
+ }
+ if (pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER) {
+ if (!FoldBinaryNumeric(cx, pn->pn_op, pn1, pn2, pn, tc))
+ return JS_FALSE;
+ }
+ }
+ break;
+
+ case TOK_UNARYOP:
+ if (pn1->pn_type == TOK_NUMBER) {
+ jsdouble d;
+ int32 i;
+
+ /* Operate on one numeric constant. */
+ d = pn1->pn_dval;
+ switch (pn->pn_op) {
+ case JSOP_BITNOT:
+ if (!js_DoubleToECMAInt32(cx, d, &i))
+ return JS_FALSE;
+ d = ~i;
+ break;
+
+ case JSOP_NEG:
+#ifdef HPUX
+ /*
+ * Negation of a zero doesn't produce a negative
+ * zero on HPUX. Perform the operation by bit
+ * twiddling.
+ */
+ JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT;
+#else
+ d = -d;
+#endif
+ break;
+
+ case JSOP_POS:
+ break;
+
+ case JSOP_NOT:
+ pn->pn_type = TOK_PRIMARY;
+ pn->pn_op = (d == 0) ? JSOP_TRUE : JSOP_FALSE;
+ pn->pn_arity = PN_NULLARY;
+ /* FALL THROUGH */
+
+ default:
+ /* Return early to dodge the common TOK_NUMBER code. */
+ return JS_TRUE;
+ }
+ pn->pn_type = TOK_NUMBER;
+ pn->pn_op = JSOP_NUMBER;
+ pn->pn_arity = PN_NULLARY;
+ pn->pn_dval = d;
+ RecycleTree(pn1, tc);
+ }
+ break;
+
+ default:;
+ }
+
+ return JS_TRUE;
+}
diff --git a/src/dom/js/jsparse.h b/src/dom/js/jsparse.h
new file mode 100644
index 000000000..1c6ff893a
--- /dev/null
+++ b/src/dom/js/jsparse.h
@@ -0,0 +1,337 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsparse_h___
+#define jsparse_h___
+/*
+ * JS parser definitions.
+ */
+#include "jsprvtd.h"
+#include "jspubtd.h"
+#include "jsscan.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * Parsing builds a tree of nodes that directs code generation. This tree is
+ * not a concrete syntax tree in all respects (for example, || and && are left
+ * associative, but (A && B && C) translates into the right-associated tree
+ * <A && <B && C>> so that code generation can emit a left-associative branch
+ * around <B && C> when A is false). Nodes are labeled by token type, with a
+ * JSOp secondary label when needed:
+ *
+ * Label Variant Members
+ * ----- ------- -------
+ * <Definitions>
+ * TOK_FUNCTION func pn_funAtom: atom holding function object containing
+ * arg and var properties. We create the function
+ * object at parse (not emit) time to specialize arg
+ * and var bytecodes early.
+ * pn_body: TOK_LC node for function body statements
+ * pn_flags: TCF_FUN_* flags (see jsemit.h) collected
+ * while parsing the function's body
+ * pn_tryCount: of try statements in function
+ *
+ * <Statements>
+ * TOK_LC list pn_head: list of pn_count statements
+ * TOK_EXPORT list pn_head: list of pn_count TOK_NAMEs or one TOK_STAR
+ * (which is not a multiply node)
+ * TOK_IMPORT list pn_head: list of pn_count sub-trees of the form
+ * a.b.*, a[b].*, a.*, a.b, or a[b] -- but never a.
+ * Each member is expressed with TOK_DOT or TOK_LB.
+ * Each sub-tree's root node has a pn_op in the set
+ * JSOP_IMPORT{ALL,PROP,ELEM}
+ * TOK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null
+ * TOK_SWITCH binary pn_left: discriminant
+ * pn_right: list of TOK_CASE nodes, with at most one
+ * TOK_DEFAULT node
+ * TOK_CASE, binary pn_left: case expr or null if TOK_DEFAULT
+ * TOK_DEFAULT pn_right: TOK_LC node for this case's statements
+ * TOK_WHILE binary pn_left: cond, pn_right: body
+ * TOK_DO binary pn_left: body, pn_right: cond
+ * TOK_FOR binary pn_left: either
+ * for/in loop: a binary TOK_IN node with
+ * pn_left: TOK_VAR or TOK_NAME to left of 'in'
+ * pn_right: object expr to right of 'in'
+ * for(;;) loop: a ternary TOK_RESERVED node with
+ * pn_kid1: init expr before first ';'
+ * pn_kid2: cond expr before second ';'
+ * pn_kid3: update expr after second ';'
+ * any kid may be null
+ * pn_right: body
+ * TOK_THROW unary pn_op: JSOP_THROW, pn_kid: exception
+ * TOK_TRY ternary pn_kid1: try block
+ * pn_kid2: catch blocks or null
+ * pn_kid3: finally block or null
+ * TOK_CATCH ternary pn_kid1: PN_NAME node for catch var (with pn_expr
+ * null or the catch guard expression)
+ * pn_kid2: more catch blocks or null
+ * pn_kid3: catch block statements
+ * TOK_BREAK name pn_atom: label or null
+ * TOK_CONTINUE name pn_atom: label or null
+ * TOK_WITH binary pn_left: head expr, pn_right: body
+ * TOK_VAR list pn_head: list of pn_count TOK_NAME nodes
+ * each name node has
+ * pn_atom: variable name
+ * pn_expr: initializer or null
+ * TOK_RETURN unary pn_kid: return expr or null
+ * TOK_SEMI unary pn_kid: expr or null statement
+ * TOK_COLON name pn_atom: label, pn_expr: labeled statement
+ *
+ * <Expressions>
+ * All left-associated binary trees of the same type are optimized into lists
+ * to avoid recursion when processing expression chains.
+ * TOK_COMMA list pn_head: list of pn_count comma-separated exprs
+ * TOK_ASSIGN binary pn_left: lvalue, pn_right: rvalue
+ * pn_op: JSOP_ADD for +=, etc.
+ * TOK_HOOK ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else
+ * TOK_OR binary pn_left: first in || chain, pn_right: rest of chain
+ * TOK_AND binary pn_left: first in && chain, pn_right: rest of chain
+ * TOK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr
+ * TOK_BITXOR binary pn_left: left-assoc ^ expr, pn_right: & expr
+ * TOK_BITAND binary pn_left: left-assoc & expr, pn_right: EQ expr
+ * TOK_EQOP binary pn_left: left-assoc EQ expr, pn_right: REL expr
+ * pn_op: JSOP_EQ, JSOP_NE, JSOP_NEW_EQ, JSOP_NEW_NE
+ * TOK_RELOP binary pn_left: left-assoc REL expr, pn_right: SH expr
+ * pn_op: JSOP_LT, JSOP_LE, JSOP_GT, JSOP_GE
+ * TOK_SHOP binary pn_left: left-assoc SH expr, pn_right: ADD expr
+ * pn_op: JSOP_LSH, JSOP_RSH, JSOP_URSH
+ * TOK_PLUS, binary pn_left: left-assoc ADD expr, pn_right: MUL expr
+ * pn_extra: if a left-associated binary TOK_PLUS
+ * tree has been flattened into a list (see above
+ * under <Expressions>), pn_extra will contain
+ * PNX_STRCAT if at least one list element is a
+ * string literal (TOK_STRING); if such a list has
+ * any non-string, non-number term, pn_extra will
+ * contain PNX_CANTFOLD.
+ * pn_
+ * TOK_MINUS pn_op: JSOP_ADD, JSOP_SUB
+ * TOK_STAR, binary pn_left: left-assoc MUL expr, pn_right: UNARY expr
+ * TOK_DIVOP pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD
+ * TOK_UNARYOP unary pn_kid: UNARY expr, pn_op: JSOP_NEG, JSOP_POS,
+ * JSOP_NOT, JSOP_BITNOT, JSOP_TYPEOF, JSOP_VOID
+ * TOK_INC, unary pn_kid: MEMBER expr
+ * TOK_DEC
+ * TOK_NEW list pn_head: list of ctor, arg1, arg2, ... argN
+ * pn_count: 1 + N (where N is number of args)
+ * ctor is a MEMBER expr
+ * TOK_DELETE unary pn_kid: MEMBER expr
+ * TOK_DOT name pn_expr: MEMBER expr to left of .
+ * pn_atom: name to right of .
+ * TOK_LB binary pn_left: MEMBER expr to left of [
+ * pn_right: expr between [ and ]
+ * TOK_LP list pn_head: list of call, arg1, arg2, ... argN
+ * pn_count: 1 + N (where N is number of args)
+ * call is a MEMBER expr naming a callable object
+ * TOK_RB list pn_head: list of pn_count array element exprs
+ * [,,] holes are represented by TOK_COMMA nodes
+ * #n=[...] produces TOK_DEFSHARP at head of list
+ * pn_extra: true if extra comma at end
+ * TOK_RC list pn_head: list of pn_count TOK_COLON nodes where
+ * each has pn_left: property id, pn_right: value
+ * #n={...} produces TOK_DEFSHARP at head of list
+ * TOK_DEFSHARP unary pn_num: jsint value of n in #n=
+ * pn_kid: null for #n=[...] and #n={...}, primary
+ * if #n=primary for function, paren, name, object
+ * literal expressions
+ * TOK_USESHARP nullary pn_num: jsint value of n in #n#
+ * TOK_RP unary pn_kid: parenthesized expression
+ * TOK_NAME, name pn_atom: name, string, or object atom
+ * TOK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT
+ * TOK_OBJECT If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
+ * with pn_slot >= 0 and pn_attrs telling const-ness
+ * TOK_NUMBER dval pn_dval: double value of numeric literal
+ * TOK_PRIMARY nullary pn_op: JSOp bytecode
+ */
+typedef enum JSParseNodeArity {
+ PN_FUNC = -3,
+ PN_LIST = -2,
+ PN_TERNARY = 3,
+ PN_BINARY = 2,
+ PN_UNARY = 1,
+ PN_NAME = -1,
+ PN_NULLARY = 0
+} JSParseNodeArity;
+
+struct JSParseNode {
+ JSTokenType pn_type;
+ JSTokenPos pn_pos;
+ JSOp pn_op;
+ ptrdiff_t pn_offset; /* first generated bytecode offset */
+ JSParseNodeArity pn_arity;
+ union {
+ struct { /* TOK_FUNCTION node */
+ JSAtom *funAtom; /* atomized function object */
+ JSParseNode *body; /* TOK_LC list of statements */
+ uint32 flags; /* accumulated tree context flags */
+ uint32 tryCount; /* count of try statements in body */
+ } func;
+ struct { /* list of next-linked nodes */
+ JSParseNode *head; /* first node in list */
+ JSParseNode **tail; /* ptr to ptr to last node in list */
+ uint32 count; /* number of nodes in list */
+ uint32 extra; /* extra comma flag for [1,2,,] */
+ } list;
+ struct { /* ternary: if, for(;;), ?: */
+ JSParseNode *kid1; /* condition, discriminant, etc. */
+ JSParseNode *kid2; /* then-part, case list, etc. */
+ JSParseNode *kid3; /* else-part, default case, etc. */
+ } ternary;
+ struct { /* two kids if binary */
+ JSParseNode *left;
+ JSParseNode *right;
+ jsval val; /* switch case value */
+ } binary;
+ struct { /* one kid if unary */
+ JSParseNode *kid;
+ jsint num; /* -1 or sharp variable number */
+ } unary;
+ struct { /* name, labeled statement, etc. */
+ JSAtom *atom; /* name or label atom, null if slot */
+ JSParseNode *expr; /* object or initializer */
+ jsint slot; /* -1 or arg or local var slot */
+ uintN attrs; /* attributes if local var or const */
+ } name;
+ jsdouble dval; /* aligned numeric literal value */
+ } pn_u;
+ JSParseNode *pn_next; /* to align dval and pn_u on RISCs */
+};
+
+#define pn_funAtom pn_u.func.funAtom
+#define pn_body pn_u.func.body
+#define pn_flags pn_u.func.flags
+#define pn_tryCount pn_u.func.tryCount
+#define pn_head pn_u.list.head
+#define pn_tail pn_u.list.tail
+#define pn_count pn_u.list.count
+#define pn_extra pn_u.list.extra
+#define pn_kid1 pn_u.ternary.kid1
+#define pn_kid2 pn_u.ternary.kid2
+#define pn_kid3 pn_u.ternary.kid3
+#define pn_left pn_u.binary.left
+#define pn_right pn_u.binary.right
+#define pn_val pn_u.binary.val
+#define pn_kid pn_u.unary.kid
+#define pn_num pn_u.unary.num
+#define pn_atom pn_u.name.atom
+#define pn_expr pn_u.name.expr
+#define pn_slot pn_u.name.slot
+#define pn_attrs pn_u.name.attrs
+#define pn_dval pn_u.dval
+
+/* PN_LIST pn_extra flags. */
+#define PNX_STRCAT 0x1 /* TOK_PLUS list has string term */
+#define PNX_CANTFOLD 0x2 /* TOK_PLUS list has unfoldable term */
+
+/*
+ * Move pn2 into pn, preserving pn->pn_pos and pn->pn_offset and handing off
+ * any kids in pn2->pn_u, by clearing pn2.
+ */
+#define PN_MOVE_NODE(pn, pn2) \
+ JS_BEGIN_MACRO \
+ (pn)->pn_type = (pn2)->pn_type; \
+ (pn)->pn_op = (pn2)->pn_op; \
+ (pn)->pn_arity = (pn2)->pn_arity; \
+ (pn)->pn_u = (pn2)->pn_u; \
+ PN_CLEAR_NODE(pn2); \
+ JS_END_MACRO
+
+#define PN_CLEAR_NODE(pn) \
+ JS_BEGIN_MACRO \
+ (pn)->pn_type = TOK_EOF; \
+ (pn)->pn_op = JSOP_NOP; \
+ (pn)->pn_arity = PN_NULLARY; \
+ JS_END_MACRO
+
+/* True if pn is a parsenode representing a literal constant. */
+#define PN_IS_CONSTANT(pn) \
+ ((pn)->pn_type == TOK_NUMBER || \
+ (pn)->pn_type == TOK_STRING || \
+ ((pn)->pn_type == TOK_PRIMARY && (pn)->pn_op != JSOP_THIS))
+
+/*
+ * Compute a pointer to the last JSParseNode element in a singly-linked list.
+ * NB: list must be non-empty for correct PN_LAST usage!
+ */
+#define PN_LAST(list) \
+ ((JSParseNode *)((char *)(list)->pn_tail - offsetof(JSParseNode, pn_next)))
+
+#define PN_INIT_LIST(list) \
+ JS_BEGIN_MACRO \
+ (list)->pn_head = NULL; \
+ (list)->pn_tail = &(list)->pn_head; \
+ (list)->pn_count = 0; \
+ JS_END_MACRO
+
+#define PN_INIT_LIST_1(list, pn) \
+ JS_BEGIN_MACRO \
+ (list)->pn_head = (pn); \
+ (list)->pn_tail = &(pn)->pn_next; \
+ (list)->pn_count = 1; \
+ JS_END_MACRO
+
+#define PN_APPEND(list, pn) \
+ JS_BEGIN_MACRO \
+ *(list)->pn_tail = (pn); \
+ (list)->pn_tail = &(pn)->pn_next; \
+ (list)->pn_count++; \
+ JS_END_MACRO
+
+/*
+ * Parse a top-level JS script.
+ *
+ * The caller must prevent the GC from running while this function is active,
+ * because atoms and function newborns are not rooted yet.
+ */
+extern JS_FRIEND_API(JSParseNode *)
+js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts);
+
+extern JS_FRIEND_API(JSBool)
+js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
+ JSCodeGenerator *cg);
+
+extern JSBool
+js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun);
+
+extern JSBool
+js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc);
+
+JS_END_EXTERN_C
+
+#endif /* jsparse_h___ */
diff --git a/src/dom/js/jsprf.c b/src/dom/js/jsprf.c
new file mode 100644
index 000000000..36bf92428
--- /dev/null
+++ b/src/dom/js/jsprf.c
@@ -0,0 +1,1212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** Portable safe sprintf code.
+**
+** Author: Kipp E.B. Hickman
+*/
+#include "jsstddef.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "jsprf.h"
+#include "jslong.h"
+#include "jsutil.h" /* Added by JSIFY */
+
+/*
+** Note: on some platforms va_list is defined as an array,
+** and requires array notation.
+*/
+#ifdef HAVE_VA_COPY
+#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar)
+#elif defined(HAVE_VA_LIST_AS_ARRAY)
+#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
+#else
+#define VARARGS_ASSIGN(foo, bar) (foo) = (bar)
+#endif
+
+/*
+** WARNING: This code may *NOT* call JS_LOG (because JS_LOG calls it)
+*/
+
+/*
+** XXX This needs to be internationalized!
+*/
+
+typedef struct SprintfStateStr SprintfState;
+
+struct SprintfStateStr {
+ int (*stuff)(SprintfState *ss, const char *sp, JSUint32 len);
+
+ char *base;
+ char *cur;
+ JSUint32 maxlen;
+
+ int (*func)(void *arg, const char *sp, JSUint32 len);
+ void *arg;
+};
+
+/*
+** Numbered Arguement State
+*/
+struct NumArgState{
+ int type; /* type of the current ap */
+ va_list ap; /* point to the corresponding position on ap */
+};
+
+#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */
+
+
+#define TYPE_INT16 0
+#define TYPE_UINT16 1
+#define TYPE_INTN 2
+#define TYPE_UINTN 3
+#define TYPE_INT32 4
+#define TYPE_UINT32 5
+#define TYPE_INT64 6
+#define TYPE_UINT64 7
+#define TYPE_STRING 8
+#define TYPE_DOUBLE 9
+#define TYPE_INTSTR 10
+#define TYPE_UNKNOWN 20
+
+#define FLAG_LEFT 0x1
+#define FLAG_SIGNED 0x2
+#define FLAG_SPACED 0x4
+#define FLAG_ZEROS 0x8
+#define FLAG_NEG 0x10
+
+/*
+** Fill into the buffer using the data in src
+*/
+static int fill2(SprintfState *ss, const char *src, int srclen, int width,
+ int flags)
+{
+ char space = ' ';
+ int rv;
+
+ width -= srclen;
+ if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */
+ if (flags & FLAG_ZEROS) {
+ space = '0';
+ }
+ while (--width >= 0) {
+ rv = (*ss->stuff)(ss, &space, 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ }
+
+ /* Copy out the source data */
+ rv = (*ss->stuff)(ss, src, (JSUint32)srclen);
+ if (rv < 0) {
+ return rv;
+ }
+
+ if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */
+ while (--width >= 0) {
+ rv = (*ss->stuff)(ss, &space, 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+** Fill a number. The order is: optional-sign zero-filling conversion-digits
+*/
+static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
+ int prec, int type, int flags)
+{
+ int zerowidth = 0;
+ int precwidth = 0;
+ int signwidth = 0;
+ int leftspaces = 0;
+ int rightspaces = 0;
+ int cvtwidth;
+ int rv;
+ char sign;
+
+ if ((type & 1) == 0) {
+ if (flags & FLAG_NEG) {
+ sign = '-';
+ signwidth = 1;
+ } else if (flags & FLAG_SIGNED) {
+ sign = '+';
+ signwidth = 1;
+ } else if (flags & FLAG_SPACED) {
+ sign = ' ';
+ signwidth = 1;
+ }
+ }
+ cvtwidth = signwidth + srclen;
+
+ if (prec > 0) {
+ if (prec > srclen) {
+ precwidth = prec - srclen; /* Need zero filling */
+ cvtwidth += precwidth;
+ }
+ }
+
+ if ((flags & FLAG_ZEROS) && (prec < 0)) {
+ if (width > cvtwidth) {
+ zerowidth = width - cvtwidth; /* Zero filling */
+ cvtwidth += zerowidth;
+ }
+ }
+
+ if (flags & FLAG_LEFT) {
+ if (width > cvtwidth) {
+ /* Space filling on the right (i.e. left adjusting) */
+ rightspaces = width - cvtwidth;
+ }
+ } else {
+ if (width > cvtwidth) {
+ /* Space filling on the left (i.e. right adjusting) */
+ leftspaces = width - cvtwidth;
+ }
+ }
+ while (--leftspaces >= 0) {
+ rv = (*ss->stuff)(ss, " ", 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ if (signwidth) {
+ rv = (*ss->stuff)(ss, &sign, 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ while (--precwidth >= 0) {
+ rv = (*ss->stuff)(ss, "0", 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ while (--zerowidth >= 0) {
+ rv = (*ss->stuff)(ss, "0", 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ rv = (*ss->stuff)(ss, src, (JSUint32)srclen);
+ if (rv < 0) {
+ return rv;
+ }
+ while (--rightspaces >= 0) {
+ rv = (*ss->stuff)(ss, " ", 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ return 0;
+}
+
+/*
+** Convert a long into its printable form
+*/
+static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
+ int type, int flags, const char *hexp)
+{
+ char cvtbuf[100];
+ char *cvt;
+ int digits;
+
+ /* according to the man page this needs to happen */
+ if ((prec == 0) && (num == 0)) {
+ return 0;
+ }
+
+ /*
+ ** Converting decimal is a little tricky. In the unsigned case we
+ ** need to stop when we hit 10 digits. In the signed case, we can
+ ** stop when the number is zero.
+ */
+ cvt = cvtbuf + sizeof(cvtbuf);
+ digits = 0;
+ while (num) {
+ int digit = (((unsigned long)num) % radix) & 0xF;
+ *--cvt = hexp[digit];
+ digits++;
+ num = (long)(((unsigned long)num) / radix);
+ }
+ if (digits == 0) {
+ *--cvt = '0';
+ digits++;
+ }
+
+ /*
+ ** Now that we have the number converted without its sign, deal with
+ ** the sign and zero padding.
+ */
+ return fill_n(ss, cvt, digits, width, prec, type, flags);
+}
+
+/*
+** Convert a 64-bit integer into its printable form
+*/
+static int cvt_ll(SprintfState *ss, JSInt64 num, int width, int prec, int radix,
+ int type, int flags, const char *hexp)
+{
+ char cvtbuf[100];
+ char *cvt;
+ int digits;
+ JSInt64 rad;
+
+ /* according to the man page this needs to happen */
+ if ((prec == 0) && (JSLL_IS_ZERO(num))) {
+ return 0;
+ }
+
+ /*
+ ** Converting decimal is a little tricky. In the unsigned case we
+ ** need to stop when we hit 10 digits. In the signed case, we can
+ ** stop when the number is zero.
+ */
+ JSLL_I2L(rad, radix);
+ cvt = cvtbuf + sizeof(cvtbuf);
+ digits = 0;
+ while (!JSLL_IS_ZERO(num)) {
+ JSInt32 digit;
+ JSInt64 quot, rem;
+ JSLL_UDIVMOD(&quot, &rem, num, rad);
+ JSLL_L2I(digit, rem);
+ *--cvt = hexp[digit & 0xf];
+ digits++;
+ num = quot;
+ }
+ if (digits == 0) {
+ *--cvt = '0';
+ digits++;
+ }
+
+ /*
+ ** Now that we have the number converted without its sign, deal with
+ ** the sign and zero padding.
+ */
+ return fill_n(ss, cvt, digits, width, prec, type, flags);
+}
+
+/*
+** Convert a double precision floating point number into its printable
+** form.
+**
+** XXX stop using sprintf to convert floating point
+*/
+static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
+{
+ char fin[20];
+ char fout[300];
+ int amount = fmt1 - fmt0;
+
+ JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
+ if (amount >= (int)sizeof(fin)) {
+ /* Totally bogus % command to sprintf. Just ignore it */
+ return 0;
+ }
+ memcpy(fin, fmt0, (size_t)amount);
+ fin[amount] = 0;
+
+ /* Convert floating point using the native sprintf code */
+#ifdef DEBUG
+ {
+ const char *p = fin;
+ while (*p) {
+ JS_ASSERT(*p != 'L');
+ p++;
+ }
+ }
+#endif
+ sprintf(fout, fin, d);
+
+ /*
+ ** This assert will catch overflow's of fout, when building with
+ ** debugging on. At least this way we can track down the evil piece
+ ** of calling code and fix it!
+ */
+ JS_ASSERT(strlen(fout) < sizeof(fout));
+
+ return (*ss->stuff)(ss, fout, strlen(fout));
+}
+
+/*
+** Convert a string into its printable form. "width" is the output
+** width. "prec" is the maximum number of characters of "s" to output,
+** where -1 means until NUL.
+*/
+static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
+ int flags)
+{
+ int slen;
+
+ if (prec == 0)
+ return 0;
+
+ /* Limit string length by precision value */
+ slen = s ? strlen(s) : 6;
+ if (prec > 0) {
+ if (prec < slen) {
+ slen = prec;
+ }
+ }
+
+ /* and away we go */
+ return fill2(ss, s ? s : "(null)", slen, width, flags);
+}
+
+/*
+** BiuldArgArray stands for Numbered Argument list Sprintf
+** for example,
+** fmp = "%4$i, %2$d, %3s, %1d";
+** the number must start from 1, and no gap among them
+*/
+
+static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray )
+{
+ int number = 0, cn = 0, i;
+ const char* p;
+ char c;
+ struct NumArgState* nas;
+
+
+ /*
+ ** first pass:
+ ** detemine how many legal % I have got, then allocate space
+ */
+
+ p = fmt;
+ *rv = 0;
+ i = 0;
+ while( ( c = *p++ ) != 0 ){
+ if( c != '%' )
+ continue;
+ if( ( c = *p++ ) == '%' ) /* skip %% case */
+ continue;
+
+ while( c != 0 ){
+ if( c > '9' || c < '0' ){
+ if( c == '$' ){ /* numbered argument csae */
+ if( i > 0 ){
+ *rv = -1;
+ return NULL;
+ }
+ number++;
+ } else { /* non-numbered argument case */
+ if( number > 0 ){
+ *rv = -1;
+ return NULL;
+ }
+ i = 1;
+ }
+ break;
+ }
+
+ c = *p++;
+ }
+ }
+
+ if( number == 0 ){
+ return NULL;
+ }
+
+
+ if( number > NAS_DEFAULT_NUM ){
+ nas = (struct NumArgState*)malloc( number * sizeof( struct NumArgState ) );
+ if( !nas ){
+ *rv = -1;
+ return NULL;
+ }
+ } else {
+ nas = nasArray;
+ }
+
+ for( i = 0; i < number; i++ ){
+ nas[i].type = TYPE_UNKNOWN;
+ }
+
+
+ /*
+ ** second pass:
+ ** set nas[].type
+ */
+
+ p = fmt;
+ while( ( c = *p++ ) != 0 ){
+ if( c != '%' ) continue;
+ c = *p++;
+ if( c == '%' ) continue;
+
+ cn = 0;
+ while( c && c != '$' ){ /* should imporve error check later */
+ cn = cn*10 + c - '0';
+ c = *p++;
+ }
+
+ if( !c || cn < 1 || cn > number ){
+ *rv = -1;
+ break;
+ }
+
+ /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
+ cn--;
+ if( nas[cn].type != TYPE_UNKNOWN )
+ continue;
+
+ c = *p++;
+
+ /* width */
+ if (c == '*') {
+ /* not supported feature, for the argument is not numbered */
+ *rv = -1;
+ break;
+ }
+
+ while ((c >= '0') && (c <= '9')) {
+ c = *p++;
+ }
+
+ /* precision */
+ if (c == '.') {
+ c = *p++;
+ if (c == '*') {
+ /* not supported feature, for the argument is not numbered */
+ *rv = -1;
+ break;
+ }
+
+ while ((c >= '0') && (c <= '9')) {
+ c = *p++;
+ }
+ }
+
+ /* size */
+ nas[cn].type = TYPE_INTN;
+ if (c == 'h') {
+ nas[cn].type = TYPE_INT16;
+ c = *p++;
+ } else if (c == 'L') {
+ /* XXX not quite sure here */
+ nas[cn].type = TYPE_INT64;
+ c = *p++;
+ } else if (c == 'l') {
+ nas[cn].type = TYPE_INT32;
+ c = *p++;
+ if (c == 'l') {
+ nas[cn].type = TYPE_INT64;
+ c = *p++;
+ }
+ }
+
+ /* format */
+ switch (c) {
+ case 'd':
+ case 'c':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ break;
+
+ case 'e':
+ case 'f':
+ case 'g':
+ nas[ cn ].type = TYPE_DOUBLE;
+ break;
+
+ case 'p':
+ /* XXX should use cpp */
+ if (sizeof(void *) == sizeof(JSInt32)) {
+ nas[ cn ].type = TYPE_UINT32;
+ } else if (sizeof(void *) == sizeof(JSInt64)) {
+ nas[ cn ].type = TYPE_UINT64;
+ } else if (sizeof(void *) == sizeof(JSIntn)) {
+ nas[ cn ].type = TYPE_UINTN;
+ } else {
+ nas[ cn ].type = TYPE_UNKNOWN;
+ }
+ break;
+
+ case 'C':
+ case 'S':
+ case 'E':
+ case 'G':
+ /* XXX not supported I suppose */
+ JS_ASSERT(0);
+ nas[ cn ].type = TYPE_UNKNOWN;
+ break;
+
+ case 's':
+ nas[ cn ].type = TYPE_STRING;
+ break;
+
+ case 'n':
+ nas[ cn ].type = TYPE_INTSTR;
+ break;
+
+ default:
+ JS_ASSERT(0);
+ nas[ cn ].type = TYPE_UNKNOWN;
+ break;
+ }
+
+ /* get a legal para. */
+ if( nas[ cn ].type == TYPE_UNKNOWN ){
+ *rv = -1;
+ break;
+ }
+ }
+
+
+ /*
+ ** third pass
+ ** fill the nas[cn].ap
+ */
+
+ if( *rv < 0 ){
+ if( nas != nasArray )
+ JS_DELETE( nas );
+ return NULL;
+ }
+
+ cn = 0;
+ while( cn < number ){
+ if( nas[cn].type == TYPE_UNKNOWN ){
+ cn++;
+ continue;
+ }
+
+ VARARGS_ASSIGN(nas[cn].ap, ap);
+
+ switch( nas[cn].type ){
+ case TYPE_INT16:
+ case TYPE_UINT16:
+ case TYPE_INTN:
+ case TYPE_UINTN: (void)va_arg( ap, JSIntn ); break;
+
+ case TYPE_INT32: (void)va_arg( ap, JSInt32 ); break;
+
+ case TYPE_UINT32: (void)va_arg( ap, JSUint32 ); break;
+
+ case TYPE_INT64: (void)va_arg( ap, JSInt64 ); break;
+
+ case TYPE_UINT64: (void)va_arg( ap, JSUint64 ); break;
+
+ case TYPE_STRING: (void)va_arg( ap, char* ); break;
+
+ case TYPE_INTSTR: (void)va_arg( ap, JSIntn* ); break;
+
+ case TYPE_DOUBLE: (void)va_arg( ap, double ); break;
+
+ default:
+ if( nas != nasArray )
+ JS_DELETE( nas );
+ *rv = -1;
+ return NULL;
+ }
+
+ cn++;
+ }
+
+
+ return nas;
+}
+
+/*
+** The workhorse sprintf code.
+*/
+static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
+{
+ char c;
+ int flags, width, prec, radix, type;
+ union {
+ char ch;
+ int i;
+ long l;
+ JSInt64 ll;
+ double d;
+ const char *s;
+ int *ip;
+ } u;
+ const char *fmt0;
+ static char *hex = "0123456789abcdef";
+ static char *HEX = "0123456789ABCDEF";
+ char *hexp;
+ int rv, i;
+ struct NumArgState* nas = NULL;
+ struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
+ char pattern[20];
+ const char* dolPt = NULL; /* in "%4$.2f", dolPt will poiont to . */
+
+
+ /*
+ ** build an argument array, IF the fmt is numbered argument
+ ** list style, to contain the Numbered Argument list pointers
+ */
+
+ nas = BuildArgArray( fmt, ap, &rv, nasArray );
+ if( rv < 0 ){
+ /* the fmt contains error Numbered Argument format, jliu@netscape.com */
+ JS_ASSERT(0);
+ return rv;
+ }
+
+ while ((c = *fmt++) != 0) {
+ if (c != '%') {
+ rv = (*ss->stuff)(ss, fmt - 1, 1);
+ if (rv < 0) {
+ return rv;
+ }
+ continue;
+ }
+ fmt0 = fmt - 1;
+
+ /*
+ ** Gobble up the % format string. Hopefully we have handled all
+ ** of the strange cases!
+ */
+ flags = 0;
+ c = *fmt++;
+ if (c == '%') {
+ /* quoting a % with %% */
+ rv = (*ss->stuff)(ss, fmt - 1, 1);
+ if (rv < 0) {
+ return rv;
+ }
+ continue;
+ }
+
+ if( nas != NULL ){
+ /* the fmt contains the Numbered Arguments feature */
+ i = 0;
+ while( c && c != '$' ){ /* should imporve error check later */
+ i = ( i * 10 ) + ( c - '0' );
+ c = *fmt++;
+ }
+
+ if( nas[i-1].type == TYPE_UNKNOWN ){
+ if( nas && ( nas != nasArray ) )
+ JS_DELETE( nas );
+ return -1;
+ }
+
+ ap = nas[i-1].ap;
+ dolPt = fmt;
+ c = *fmt++;
+ }
+
+ /*
+ * Examine optional flags. Note that we do not implement the
+ * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is
+ * somewhat ambiguous and not ideal, which is perhaps why
+ * the various sprintf() implementations are inconsistent
+ * on this feature.
+ */
+ while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
+ if (c == '-') flags |= FLAG_LEFT;
+ if (c == '+') flags |= FLAG_SIGNED;
+ if (c == ' ') flags |= FLAG_SPACED;
+ if (c == '0') flags |= FLAG_ZEROS;
+ c = *fmt++;
+ }
+ if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
+ if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
+
+ /* width */
+ if (c == '*') {
+ c = *fmt++;
+ width = va_arg(ap, int);
+ } else {
+ width = 0;
+ while ((c >= '0') && (c <= '9')) {
+ width = (width * 10) + (c - '0');
+ c = *fmt++;
+ }
+ }
+
+ /* precision */
+ prec = -1;
+ if (c == '.') {
+ c = *fmt++;
+ if (c == '*') {
+ c = *fmt++;
+ prec = va_arg(ap, int);
+ } else {
+ prec = 0;
+ while ((c >= '0') && (c <= '9')) {
+ prec = (prec * 10) + (c - '0');
+ c = *fmt++;
+ }
+ }
+ }
+
+ /* size */
+ type = TYPE_INTN;
+ if (c == 'h') {
+ type = TYPE_INT16;
+ c = *fmt++;
+ } else if (c == 'L') {
+ /* XXX not quite sure here */
+ type = TYPE_INT64;
+ c = *fmt++;
+ } else if (c == 'l') {
+ type = TYPE_INT32;
+ c = *fmt++;
+ if (c == 'l') {
+ type = TYPE_INT64;
+ c = *fmt++;
+ }
+ }
+
+ /* format */
+ hexp = hex;
+ switch (c) {
+ case 'd': case 'i': /* decimal/integer */
+ radix = 10;
+ goto fetch_and_convert;
+
+ case 'o': /* octal */
+ radix = 8;
+ type |= 1;
+ goto fetch_and_convert;
+
+ case 'u': /* unsigned decimal */
+ radix = 10;
+ type |= 1;
+ goto fetch_and_convert;
+
+ case 'x': /* unsigned hex */
+ radix = 16;
+ type |= 1;
+ goto fetch_and_convert;
+
+ case 'X': /* unsigned HEX */
+ radix = 16;
+ hexp = HEX;
+ type |= 1;
+ goto fetch_and_convert;
+
+ fetch_and_convert:
+ switch (type) {
+ case TYPE_INT16:
+ u.l = va_arg(ap, int);
+ if (u.l < 0) {
+ u.l = -u.l;
+ flags |= FLAG_NEG;
+ }
+ goto do_long;
+ case TYPE_UINT16:
+ u.l = va_arg(ap, int) & 0xffff;
+ goto do_long;
+ case TYPE_INTN:
+ u.l = va_arg(ap, int);
+ if (u.l < 0) {
+ u.l = -u.l;
+ flags |= FLAG_NEG;
+ }
+ goto do_long;
+ case TYPE_UINTN:
+ u.l = (long)va_arg(ap, unsigned int);
+ goto do_long;
+
+ case TYPE_INT32:
+ u.l = va_arg(ap, JSInt32);
+ if (u.l < 0) {
+ u.l = -u.l;
+ flags |= FLAG_NEG;
+ }
+ goto do_long;
+ case TYPE_UINT32:
+ u.l = (long)va_arg(ap, JSUint32);
+ do_long:
+ rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
+ if (rv < 0) {
+ return rv;
+ }
+ break;
+
+ case TYPE_INT64:
+ u.ll = va_arg(ap, JSInt64);
+ if (!JSLL_GE_ZERO(u.ll)) {
+ JSLL_NEG(u.ll, u.ll);
+ flags |= FLAG_NEG;
+ }
+ goto do_longlong;
+ case TYPE_UINT64:
+ u.ll = va_arg(ap, JSUint64);
+ do_longlong:
+ rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
+ if (rv < 0) {
+ return rv;
+ }
+ break;
+ }
+ break;
+
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ u.d = va_arg(ap, double);
+ if( nas != NULL ){
+ i = fmt - dolPt;
+ if( i < (int)sizeof( pattern ) ){
+ pattern[0] = '%';
+ memcpy( &pattern[1], dolPt, (size_t)i );
+ rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
+ }
+ } else
+ rv = cvt_f(ss, u.d, fmt0, fmt);
+
+ if (rv < 0) {
+ return rv;
+ }
+ break;
+
+ case 'c':
+ u.ch = va_arg(ap, int);
+ if ((flags & FLAG_LEFT) == 0) {
+ while (width-- > 1) {
+ rv = (*ss->stuff)(ss, " ", 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ }
+ rv = (*ss->stuff)(ss, &u.ch, 1);
+ if (rv < 0) {
+ return rv;
+ }
+ if (flags & FLAG_LEFT) {
+ while (width-- > 1) {
+ rv = (*ss->stuff)(ss, " ", 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ }
+ break;
+
+ case 'p':
+ if (sizeof(void *) == sizeof(JSInt32)) {
+ type = TYPE_UINT32;
+ } else if (sizeof(void *) == sizeof(JSInt64)) {
+ type = TYPE_UINT64;
+ } else if (sizeof(void *) == sizeof(int)) {
+ type = TYPE_UINTN;
+ } else {
+ JS_ASSERT(0);
+ break;
+ }
+ radix = 16;
+ goto fetch_and_convert;
+
+#if 0
+ case 'C':
+ case 'S':
+ case 'E':
+ case 'G':
+ /* XXX not supported I suppose */
+ JS_ASSERT(0);
+ break;
+#endif
+
+ case 's':
+ u.s = va_arg(ap, const char*);
+ rv = cvt_s(ss, u.s, width, prec, flags);
+ if (rv < 0) {
+ return rv;
+ }
+ break;
+
+ case 'n':
+ u.ip = va_arg(ap, int*);
+ if (u.ip) {
+ *u.ip = ss->cur - ss->base;
+ }
+ break;
+
+ default:
+ /* Not a % token after all... skip it */
+#if 0
+ JS_ASSERT(0);
+#endif
+ rv = (*ss->stuff)(ss, "%", 1);
+ if (rv < 0) {
+ return rv;
+ }
+ rv = (*ss->stuff)(ss, fmt - 1, 1);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ }
+
+ /* Stuff trailing NUL */
+ rv = (*ss->stuff)(ss, "\0", 1);
+
+ if( nas && ( nas != nasArray ) ){
+ JS_DELETE( nas );
+ }
+
+ return rv;
+}
+
+/************************************************************************/
+
+static int FuncStuff(SprintfState *ss, const char *sp, JSUint32 len)
+{
+ int rv;
+
+ rv = (*ss->func)(ss->arg, sp, len);
+ if (rv < 0) {
+ return rv;
+ }
+ ss->maxlen += len;
+ return 0;
+}
+
+JS_PUBLIC_API(JSUint32) JS_sxprintf(JSStuffFunc func, void *arg,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, fmt);
+ rv = JS_vsxprintf(func, arg, fmt, ap);
+ va_end(ap);
+ return rv;
+}
+
+JS_PUBLIC_API(JSUint32) JS_vsxprintf(JSStuffFunc func, void *arg,
+ const char *fmt, va_list ap)
+{
+ SprintfState ss;
+ int rv;
+
+ ss.stuff = FuncStuff;
+ ss.func = func;
+ ss.arg = arg;
+ ss.maxlen = 0;
+ rv = dosprintf(&ss, fmt, ap);
+ return (rv < 0) ? (JSUint32)-1 : ss.maxlen;
+}
+
+/*
+** Stuff routine that automatically grows the malloc'd output buffer
+** before it overflows.
+*/
+static int GrowStuff(SprintfState *ss, const char *sp, JSUint32 len)
+{
+ ptrdiff_t off;
+ char *newbase;
+ JSUint32 newlen;
+
+ off = ss->cur - ss->base;
+ if (off + len >= ss->maxlen) {
+ /* Grow the buffer */
+ newlen = ss->maxlen + ((len > 32) ? len : 32);
+ if (ss->base) {
+ newbase = (char*) realloc(ss->base, newlen);
+ } else {
+ newbase = (char*) malloc(newlen);
+ }
+ if (!newbase) {
+ /* Ran out of memory */
+ return -1;
+ }
+ ss->base = newbase;
+ ss->maxlen = newlen;
+ ss->cur = ss->base + off;
+ }
+
+ /* Copy data */
+ while (len) {
+ --len;
+ *ss->cur++ = *sp++;
+ }
+ JS_ASSERT((JSUint32)(ss->cur - ss->base) <= ss->maxlen);
+ return 0;
+}
+
+/*
+** sprintf into a malloc'd buffer
+*/
+JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
+{
+ va_list ap;
+ char *rv;
+
+ va_start(ap, fmt);
+ rv = JS_vsmprintf(fmt, ap);
+ va_end(ap);
+ return rv;
+}
+
+/*
+** Free memory allocated, for the caller, by JS_smprintf
+*/
+JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
+{
+ JS_DELETE(mem);
+}
+
+JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
+{
+ SprintfState ss;
+ int rv;
+
+ ss.stuff = GrowStuff;
+ ss.base = 0;
+ ss.cur = 0;
+ ss.maxlen = 0;
+ rv = dosprintf(&ss, fmt, ap);
+ if (rv < 0) {
+ if (ss.base) {
+ JS_DELETE(ss.base);
+ }
+ return 0;
+ }
+ return ss.base;
+}
+
+/*
+** Stuff routine that discards overflow data
+*/
+static int LimitStuff(SprintfState *ss, const char *sp, JSUint32 len)
+{
+ JSUint32 limit = ss->maxlen - (ss->cur - ss->base);
+
+ if (len > limit) {
+ len = limit;
+ }
+ while (len) {
+ --len;
+ *ss->cur++ = *sp++;
+ }
+ return 0;
+}
+
+/*
+** sprintf into a fixed size buffer. Make sure there is a NUL at the end
+** when finished.
+*/
+JS_PUBLIC_API(JSUint32) JS_snprintf(char *out, JSUint32 outlen, const char *fmt, ...)
+{
+ va_list ap;
+ int rv;
+
+ JS_ASSERT((JSInt32)outlen > 0);
+ if ((JSInt32)outlen <= 0) {
+ return 0;
+ }
+
+ va_start(ap, fmt);
+ rv = JS_vsnprintf(out, outlen, fmt, ap);
+ va_end(ap);
+ return rv;
+}
+
+JS_PUBLIC_API(JSUint32) JS_vsnprintf(char *out, JSUint32 outlen,const char *fmt,
+ va_list ap)
+{
+ SprintfState ss;
+ JSUint32 n;
+
+ JS_ASSERT((JSInt32)outlen > 0);
+ if ((JSInt32)outlen <= 0) {
+ return 0;
+ }
+
+ ss.stuff = LimitStuff;
+ ss.base = out;
+ ss.cur = out;
+ ss.maxlen = outlen;
+ (void) dosprintf(&ss, fmt, ap);
+
+ /* If we added chars, and we didn't append a null, do it now. */
+ if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') )
+ *(--ss.cur) = '\0';
+
+ n = ss.cur - ss.base;
+ return n ? n - 1 : n;
+}
+
+JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...)
+{
+ va_list ap;
+ char *rv;
+
+ va_start(ap, fmt);
+ rv = JS_vsprintf_append(last, fmt, ap);
+ va_end(ap);
+ return rv;
+}
+
+JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap)
+{
+ SprintfState ss;
+ int rv;
+
+ ss.stuff = GrowStuff;
+ if (last) {
+ int lastlen = strlen(last);
+ ss.base = last;
+ ss.cur = last + lastlen;
+ ss.maxlen = lastlen;
+ } else {
+ ss.base = 0;
+ ss.cur = 0;
+ ss.maxlen = 0;
+ }
+ rv = dosprintf(&ss, fmt, ap);
+ if (rv < 0) {
+ if (ss.base) {
+ JS_DELETE(ss.base);
+ }
+ return 0;
+ }
+ return ss.base;
+}
+
diff --git a/src/dom/js/jsprf.h b/src/dom/js/jsprf.h
new file mode 100644
index 000000000..e8cc46c0c
--- /dev/null
+++ b/src/dom/js/jsprf.h
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsprf_h___
+#define jsprf_h___
+
+/*
+** API for PR printf like routines. Supports the following formats
+** %d - decimal
+** %u - unsigned decimal
+** %x - unsigned hex
+** %X - unsigned uppercase hex
+** %o - unsigned octal
+** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above
+** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above
+** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above
+** %s - string
+** %c - character
+** %p - pointer (deals with machine dependent pointer size)
+** %f - float
+** %g - float
+*/
+#include "jstypes.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+JS_BEGIN_EXTERN_C
+
+/*
+** sprintf into a fixed size buffer. Guarantees that a NUL is at the end
+** of the buffer. Returns the length of the written output, NOT including
+** the NUL, or (JSUint32)-1 if an error occurs.
+*/
+extern JS_PUBLIC_API(JSUint32) JS_snprintf(char *out, JSUint32 outlen, const char *fmt, ...);
+
+/*
+** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
+** buffer on success, NULL on failure. Call "JS_smprintf_free" to release
+** the memory returned.
+*/
+extern JS_PUBLIC_API(char*) JS_smprintf(const char *fmt, ...);
+
+/*
+** Free the memory allocated, for the caller, by JS_smprintf
+*/
+extern JS_PUBLIC_API(void) JS_smprintf_free(char *mem);
+
+/*
+** "append" sprintf into a malloc'd buffer. "last" is the last value of
+** the malloc'd buffer. sprintf will append data to the end of last,
+** growing it as necessary using realloc. If last is NULL, JS_sprintf_append
+** will allocate the initial string. The return value is the new value of
+** last for subsequent calls, or NULL if there is a malloc failure.
+*/
+extern JS_PUBLIC_API(char*) JS_sprintf_append(char *last, const char *fmt, ...);
+
+/*
+** sprintf into a function. The function "f" is called with a string to
+** place into the output. "arg" is an opaque pointer used by the stuff
+** function to hold any state needed to do the storage of the output
+** data. The return value is a count of the number of characters fed to
+** the stuff function, or (JSUint32)-1 if an error occurs.
+*/
+typedef JSIntn (*JSStuffFunc)(void *arg, const char *s, JSUint32 slen);
+
+extern JS_PUBLIC_API(JSUint32) JS_sxprintf(JSStuffFunc f, void *arg, const char *fmt, ...);
+
+/*
+** va_list forms of the above.
+*/
+extern JS_PUBLIC_API(JSUint32) JS_vsnprintf(char *out, JSUint32 outlen, const char *fmt, va_list ap);
+extern JS_PUBLIC_API(char*) JS_vsmprintf(const char *fmt, va_list ap);
+extern JS_PUBLIC_API(char*) JS_vsprintf_append(char *last, const char *fmt, va_list ap);
+extern JS_PUBLIC_API(JSUint32) JS_vsxprintf(JSStuffFunc f, void *arg, const char *fmt, va_list ap);
+
+/*
+***************************************************************************
+** FUNCTION: JS_sscanf
+** DESCRIPTION:
+** JS_sscanf() scans the input character string, performs data
+** conversions, and stores the converted values in the data objects
+** pointed to by its arguments according to the format control
+** string.
+**
+** JS_sscanf() behaves the same way as the sscanf() function in the
+** Standard C Library (stdio.h), with the following exceptions:
+** - JS_sscanf() handles the NSPR integer and floating point types,
+** such as JSInt16, JSInt32, JSInt64, and JSFloat64, whereas
+** sscanf() handles the standard C types like short, int, long,
+** and double.
+** - JS_sscanf() has no multibyte character support, while sscanf()
+** does.
+** INPUTS:
+** const char *buf
+** a character string holding the input to scan
+** const char *fmt
+** the format control string for the conversions
+** ...
+** variable number of arguments, each of them is a pointer to
+** a data object in which the converted value will be stored
+** OUTPUTS: none
+** RETURNS: JSInt32
+** The number of values converted and stored.
+** RESTRICTIONS:
+** Multibyte characters in 'buf' or 'fmt' are not allowed.
+***************************************************************************
+*/
+
+extern JS_PUBLIC_API(JSInt32) JS_sscanf(const char *buf, const char *fmt, ...);
+
+JS_END_EXTERN_C
+
+#endif /* jsprf_h___ */
diff --git a/src/dom/js/jsprvtd.h b/src/dom/js/jsprvtd.h
new file mode 100644
index 000000000..f5f1e77f6
--- /dev/null
+++ b/src/dom/js/jsprvtd.h
@@ -0,0 +1,174 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsprvtd_h___
+#define jsprvtd_h___
+/*
+ * JS private typename definitions.
+ *
+ * This header is included only in other .h files, for convenience and for
+ * simplicity of type naming. The alternative for structures is to use tags,
+ * which are named the same as their typedef names (legal in C/C++, and less
+ * noisy than suffixing the typedef name with "Struct" or "Str"). Instead,
+ * all .h files that include this file may use the same typedef name, whether
+ * declaring a pointer to struct type, or defining a member of struct type.
+ *
+ * A few fundamental scalar types are defined here too. Neither the scalar
+ * nor the struct typedefs should change much, therefore the nearly-global
+ * make dependency induced by this file should not prove painful.
+ */
+
+#include "jspubtd.h"
+
+/* Scalar typedefs. */
+typedef uint8 jsbytecode;
+typedef uint8 jssrcnote;
+typedef uint32 jsatomid;
+
+/* Struct typedefs. */
+typedef struct JSArgumentFormatMap JSArgumentFormatMap;
+typedef struct JSCodeGenerator JSCodeGenerator;
+typedef struct JSDependentString JSDependentString;
+typedef struct JSGCLockHashEntry JSGCLockHashEntry;
+typedef struct JSGCRootHashEntry JSGCRootHashEntry;
+typedef struct JSGCThing JSGCThing;
+typedef struct JSParseNode JSParseNode;
+typedef struct JSSharpObjectMap JSSharpObjectMap;
+typedef struct JSToken JSToken;
+typedef struct JSTokenPos JSTokenPos;
+typedef struct JSTokenPtr JSTokenPtr;
+typedef struct JSTokenStream JSTokenStream;
+typedef struct JSTreeContext JSTreeContext;
+typedef struct JSTryNote JSTryNote;
+
+/* Friend "Advanced API" typedefs. */
+typedef struct JSAtom JSAtom;
+typedef struct JSAtomList JSAtomList;
+typedef struct JSAtomListElement JSAtomListElement;
+typedef struct JSAtomMap JSAtomMap;
+typedef struct JSAtomState JSAtomState;
+typedef struct JSCodeSpec JSCodeSpec;
+typedef struct JSPrinter JSPrinter;
+typedef struct JSRegExp JSRegExp;
+typedef struct JSRegExpStatics JSRegExpStatics;
+typedef struct JSScope JSScope;
+typedef struct JSScopeOps JSScopeOps;
+typedef struct JSScopeProperty JSScopeProperty;
+typedef struct JSStackFrame JSStackFrame;
+typedef struct JSStackHeader JSStackHeader;
+typedef struct JSSubString JSSubString;
+
+/* "Friend" types used by jscntxt.h and jsdbgapi.h. */
+typedef enum JSTrapStatus {
+ JSTRAP_ERROR,
+ JSTRAP_CONTINUE,
+ JSTRAP_RETURN,
+ JSTRAP_THROW,
+ JSTRAP_LIMIT
+} JSTrapStatus;
+
+typedef JSTrapStatus
+(* JS_DLL_CALLBACK JSTrapHandler)(JSContext *cx, JSScript *script, jsbytecode *pc,
+ jsval *rval, void *closure);
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSWatchPointHandler)(JSContext *cx, JSObject *obj, jsval id,
+ jsval old, jsval *newp, void *closure);
+
+/* called just after script creation */
+typedef void
+(* JS_DLL_CALLBACK JSNewScriptHook)(JSContext *cx,
+ const char *filename, /* URL of script */
+ uintN lineno, /* line script starts */
+ JSScript *script,
+ JSFunction *fun,
+ void *callerdata);
+
+/* called just before script destruction */
+typedef void
+(* JS_DLL_CALLBACK JSDestroyScriptHook)(JSContext *cx,
+ JSScript *script,
+ void *callerdata);
+
+typedef void
+(* JS_DLL_CALLBACK JSSourceHandler)(const char *filename, uintN lineno,
+ jschar *str, size_t length,
+ void **listenerTSData, void *closure);
+
+/*
+* This hook captures high level script execution and function calls
+* (JS or native).
+* It is used by JS_SetExecuteHook to hook top level scripts and by
+* JS_SetCallHook to hook function calls.
+* It will get called twice per script or function call:
+* just before execution begins and just after it finishes. In both cases
+* the 'current' frame is that of the executing code.
+*
+* The 'before' param is JS_TRUE for the hook invocation before the execution
+* and JS_FALSE for the invocation after the code has run.
+*
+* The 'ok' param is significant only on the post execution invocation to
+* signify whether or not the code completed 'normally'.
+*
+* The 'closure' param is as passed to JS_SetExecuteHook or JS_SetCallHook
+* for the 'before'invocation, but is whatever value is returned from that
+* invocation for the 'after' invocation. Thus, the hook implementor *could*
+* allocate a stucture in the 'before' invocation and return a pointer
+* to that structure. The pointer would then be handed to the hook for
+* the 'after' invocation. Alternately, the 'before' could just return the
+* same value as in 'closure' to cause the 'after' invocation to be called
+* with the same 'closure' value as the 'before'.
+*
+* Returning NULL in the 'before' hook will cause the 'after' hook to
+* NOT be called.
+*/
+
+typedef void *
+(* JS_DLL_CALLBACK JSInterpreterHook)(JSContext *cx, JSStackFrame *fp, JSBool before,
+ JSBool *ok, void *closure);
+
+typedef void
+(* JS_DLL_CALLBACK JSObjectHook)(JSContext *cx, JSObject *obj, JSBool isNew,
+ void *closure);
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSDebugErrorHook)(JSContext *cx, const char *message,
+ JSErrorReport *report, void *closure);
+
+#endif /* jsprvtd_h___ */
diff --git a/src/dom/js/jspubtd.h b/src/dom/js/jspubtd.h
new file mode 100644
index 000000000..e3a1a38b5
--- /dev/null
+++ b/src/dom/js/jspubtd.h
@@ -0,0 +1,564 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jspubtd_h___
+#define jspubtd_h___
+/*
+ * JS public API typedefs.
+ */
+#include "jstypes.h"
+#include "jscompat.h"
+
+JS_BEGIN_EXTERN_C
+
+/* Scalar typedefs. */
+typedef uint16 jschar;
+typedef int32 jsint;
+typedef uint32 jsuint;
+typedef float64 jsdouble;
+typedef jsword jsval;
+typedef jsword jsid;
+typedef int32 jsrefcount; /* PRInt32 if JS_THREADSAFE, see jslock.h */
+
+/*
+ * Run-time version enumeration. See jsconfig.h for compile-time counterparts
+ * to these values that may be selected by the JS_VERSION macro, and tested by
+ * #if expressions.
+ */
+typedef enum JSVersion {
+ JSVERSION_1_0 = 100,
+ JSVERSION_1_1 = 110,
+ JSVERSION_1_2 = 120,
+ JSVERSION_1_3 = 130,
+ JSVERSION_1_4 = 140,
+ JSVERSION_ECMA_3 = 148,
+ JSVERSION_1_5 = 150,
+ JSVERSION_DEFAULT = 0,
+ JSVERSION_UNKNOWN = -1
+} JSVersion;
+
+#define JSVERSION_IS_ECMA(version) \
+ ((version) == JSVERSION_DEFAULT || (version) >= JSVERSION_1_3)
+
+/* Result of typeof operator enumeration. */
+typedef enum JSType {
+ JSTYPE_VOID, /* undefined */
+ JSTYPE_OBJECT, /* object */
+ JSTYPE_FUNCTION, /* function */
+ JSTYPE_STRING, /* string */
+ JSTYPE_NUMBER, /* number */
+ JSTYPE_BOOLEAN, /* boolean */
+ JSTYPE_LIMIT
+} JSType;
+
+/* JSObjectOps.checkAccess mode enumeration. */
+typedef enum JSAccessMode {
+ JSACC_PROTO = 0, /* XXXbe redundant w.r.t. id */
+ JSACC_PARENT = 1, /* XXXbe redundant w.r.t. id */
+ JSACC_IMPORT = 2, /* import foo.bar */
+ JSACC_WATCH = 3, /* a watchpoint on object foo for id 'bar' */
+ JSACC_READ = 4, /* a "get" of foo.bar */
+ JSACC_WRITE = 8, /* a "set" of foo.bar = baz */
+ JSACC_LIMIT
+} JSAccessMode;
+
+#define JSACC_TYPEMASK (JSACC_WRITE - 1)
+
+/*
+ * This enum type is used to control the behavior of a JSObject property
+ * iterator function that has type JSNewEnumerate.
+ */
+typedef enum JSIterateOp {
+ JSENUMERATE_INIT, /* Create new iterator state */
+ JSENUMERATE_NEXT, /* Iterate once */
+ JSENUMERATE_DESTROY /* Destroy iterator state */
+} JSIterateOp;
+
+/* Struct typedefs. */
+typedef struct JSClass JSClass;
+typedef struct JSConstDoubleSpec JSConstDoubleSpec;
+typedef struct JSContext JSContext;
+typedef struct JSErrorReport JSErrorReport;
+typedef struct JSFunction JSFunction;
+typedef struct JSFunctionSpec JSFunctionSpec;
+typedef struct JSIdArray JSIdArray;
+typedef struct JSProperty JSProperty;
+typedef struct JSPropertySpec JSPropertySpec;
+typedef struct JSObject JSObject;
+typedef struct JSObjectMap JSObjectMap;
+typedef struct JSObjectOps JSObjectOps;
+typedef struct JSRuntime JSRuntime;
+typedef struct JSRuntime JSTaskState; /* XXX deprecated name */
+typedef struct JSScript JSScript;
+typedef struct JSString JSString;
+typedef struct JSXDRState JSXDRState;
+typedef struct JSExceptionState JSExceptionState;
+typedef struct JSLocaleCallbacks JSLocaleCallbacks;
+
+/* JSClass (and JSObjectOps where appropriate) function pointer typedefs. */
+
+/*
+ * Add, delete, get or set a property named by id in obj. Note the jsval id
+ * type -- id may be a string (Unicode property identifier) or an int (element
+ * index). The *vp out parameter, on success, is the new property value after
+ * an add, get, or set. After a successful delete, *vp is JSVAL_FALSE iff
+ * obj[id] can't be deleted (because it's permanent).
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSPropertyOp)(JSContext *cx, JSObject *obj, jsval id,
+ jsval *vp);
+
+/*
+ * This function type is used for callbacks that enumerate the properties of
+ * a JSObject. The behavior depends on the value of enum_op:
+ *
+ * JSENUMERATE_INIT
+ * A new, opaque iterator state should be allocated and stored in *statep.
+ * (You can use PRIVATE_TO_JSVAL() to tag the pointer to be stored).
+ *
+ * The number of properties that will be enumerated should be returned as
+ * an integer jsval in *idp, if idp is non-null, and provided the number of
+ * enumerable properties is known. If idp is non-null and the number of
+ * enumerable properties can't be computed in advance, *idp should be set
+ * to JSVAL_ZERO.
+ *
+ * JSENUMERATE_NEXT
+ * A previously allocated opaque iterator state is passed in via statep.
+ * Return the next jsid in the iteration using *idp. The opaque iterator
+ * state pointed at by statep is destroyed and *statep is set to JSVAL_NULL
+ * if there are no properties left to enumerate.
+ *
+ * JSENUMERATE_DESTROY
+ * Destroy the opaque iterator state previously allocated in *statep by a
+ * call to this function when enum_op was JSENUMERATE_INIT.
+ *
+ * The return value is used to indicate success, with a value of JS_FALSE
+ * indicating failure.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSNewEnumerateOp)(JSContext *cx, JSObject *obj,
+ JSIterateOp enum_op,
+ jsval *statep, jsid *idp);
+
+/*
+ * The old-style JSClass.enumerate op should define all lazy properties not
+ * yet reflected in obj.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSEnumerateOp)(JSContext *cx, JSObject *obj);
+
+/*
+ * Resolve a lazy property named by id in obj by defining it directly in obj.
+ * Lazy properties are those reflected from some peer native property space
+ * (e.g., the DOM attributes for a given node reflected as obj) on demand.
+ *
+ * JS looks for a property in an object, and if not found, tries to resolve
+ * the given id. If resolve succeeds, the engine looks again in case resolve
+ * defined obj[id]. If no such property exists directly in obj, the process
+ * is repeated with obj's prototype, etc.
+ *
+ * NB: JSNewResolveOp provides a cheaper way to resolve lazy properties.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSResolveOp)(JSContext *cx, JSObject *obj, jsval id);
+
+/*
+ * Like JSResolveOp, but flags provide contextual information as follows:
+ *
+ * JSRESOLVE_QUALIFIED a qualified property id: obj.id or obj[id], not id
+ * JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment
+ *
+ * The *objp out parameter, on success, should be null to indicate that id
+ * was not resolved; and non-null, referring to obj or one of its prototypes,
+ * if id was resolved.
+ *
+ * This hook instead of JSResolveOp is called via the JSClass.resolve member
+ * if JSCLASS_NEW_RESOLVE is set in JSClass.flags.
+ *
+ * Setting JSCLASS_NEW_RESOLVE and JSCLASS_NEW_RESOLVE_GETS_START further
+ * extends this hook by passing in the starting object on the prototype chain
+ * via *objp. Thus a resolve hook implementation may define the property id
+ * being resolved in the object in which the id was first sought, rather than
+ * in a prototype object whose class led to the resolve hook being called.
+ *
+ * When using JSCLASS_NEW_RESOLVE_GETS_START, the resolve hook must therefore
+ * null *objp to signify "not resolved". With only JSCLASS_NEW_RESOLVE and no
+ * JSCLASS_NEW_RESOLVE_GETS_START, the hook can assume *objp is null on entry.
+ * This is not good practice, but enough existing hook implementations count
+ * on it that we can't break compatibility by passing the starting object in
+ * *objp without a new JSClass flag.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSNewResolveOp)(JSContext *cx, JSObject *obj, jsval id,
+ uintN flags, JSObject **objp);
+
+/*
+ * Convert obj to the given type, returning true with the resulting value in
+ * *vp on success, and returning false on error or exception.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSConvertOp)(JSContext *cx, JSObject *obj, JSType type,
+ jsval *vp);
+
+/*
+ * Finalize obj, which the garbage collector has determined to be unreachable
+ * from other live objects or from GC roots. Obviously, finalizers must never
+ * store a reference to obj.
+ */
+typedef void
+(* JS_DLL_CALLBACK JSFinalizeOp)(JSContext *cx, JSObject *obj);
+
+/*
+ * Used by JS_AddExternalStringFinalizer and JS_RemoveExternalStringFinalizer
+ * to extend and reduce the set of string types finalized by the GC.
+ */
+typedef void
+(* JS_DLL_CALLBACK JSStringFinalizeOp)(JSContext *cx, JSString *str);
+
+/*
+ * The signature for JSClass.getObjectOps, used by JS_NewObject's internals
+ * to discover the set of high-level object operations to use for new objects
+ * of the given class. All native objects have a JSClass, which is stored as
+ * a private (int-tagged) pointer in obj->slots[JSSLOT_CLASS]. In contrast,
+ * all native and host objects have a JSObjectMap at obj->map, which may be
+ * shared among a number of objects, and which contains the JSObjectOps *ops
+ * pointer used to dispatch object operations from API calls.
+ *
+ * Thus JSClass (which pre-dates JSObjectOps in the API) provides a low-level
+ * interface to class-specific code and data, while JSObjectOps allows for a
+ * higher level of operation, which does not use the object's class except to
+ * find the class's JSObjectOps struct, by calling clasp->getObjectOps.
+ *
+ * If this seems backwards, that's because it is! API compatibility requires
+ * a JSClass *clasp parameter to JS_NewObject, etc. Most host objects do not
+ * need to implement the larger JSObjectOps, and can share the common JSScope
+ * code and data used by the native (js_ObjectOps, see jsobj.c) ops.
+ */
+typedef JSObjectOps *
+(* JS_DLL_CALLBACK JSGetObjectOps)(JSContext *cx, JSClass *clasp);
+
+/*
+ * JSClass.checkAccess type: check whether obj[id] may be accessed per mode,
+ * returning false on error/exception, true on success with obj[id]'s last-got
+ * value in *vp, and its attributes in *attrsp. As for JSPropertyOp above, id
+ * is either a string or an int jsval.
+ *
+ * See JSCheckAccessIdOp, below, for the JSObjectOps counterpart, which takes
+ * a jsid (a tagged int or aligned, unique identifier pointer) rather than a
+ * jsval. The native js_ObjectOps.checkAccess simply forwards to the object's
+ * clasp->checkAccess, so that both JSClass and JSObjectOps implementors may
+ * specialize access checks.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSCheckAccessOp)(JSContext *cx, JSObject *obj, jsval id,
+ JSAccessMode mode, jsval *vp);
+
+/*
+ * Encode or decode an object, given an XDR state record representing external
+ * data. See jsxdrapi.h.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSXDRObjectOp)(JSXDRState *xdr, JSObject **objp);
+
+/*
+ * Check whether v is an instance of obj. Return false on error or exception,
+ * true on success with JS_TRUE in *bp if v is an instance of obj, JS_FALSE in
+ * *bp otherwise.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSHasInstanceOp)(JSContext *cx, JSObject *obj, jsval v,
+ JSBool *bp);
+
+/*
+ * Function type for JSClass.mark and JSObjectOps.mark, called from the GC to
+ * scan live GC-things reachable from obj's private data structure. For each
+ * such thing, a mark implementation must call
+ *
+ * JS_MarkGCThing(cx, thing, name, arg);
+ *
+ * The trailing name and arg parameters are used for GC_MARK_DEBUG-mode heap
+ * dumping and ref-path tracing. The mark function should pass a (typically
+ * literal) string naming the private data member for name, and it must pass
+ * the opaque arg parameter through from its caller.
+ *
+ * For the JSObjectOps.mark hook, the return value is the number of slots at
+ * obj->slots to scan. For JSClass.mark, the return value is ignored.
+ *
+ * NB: JSMarkOp implementations cannot allocate new GC-things (JS_NewObject
+ * called from a mark function will fail silently, e.g.).
+ */
+typedef uint32
+(* JS_DLL_CALLBACK JSMarkOp)(JSContext *cx, JSObject *obj, void *arg);
+
+/* JSObjectOps function pointer typedefs. */
+
+/*
+ * Create a new subclass of JSObjectMap (see jsobj.h), with the nrefs and ops
+ * members initialized from the same-named parameters, and with the nslots and
+ * freeslot members initialized according to ops and clasp. Return null on
+ * error, non-null on success.
+ *
+ * JSObjectMaps are reference-counted by generic code in the engine. Usually,
+ * the nrefs parameter to JSObjectOps.newObjectMap will be 1, to count the ref
+ * returned to the caller on success. After a successful construction, some
+ * number of js_HoldObjectMap and js_DropObjectMap calls ensue. When nrefs
+ * reaches 0 due to a js_DropObjectMap call, JSObjectOps.destroyObjectMap will
+ * be called to dispose of the map.
+ */
+typedef JSObjectMap *
+(* JS_DLL_CALLBACK JSNewObjectMapOp)(JSContext *cx, jsrefcount nrefs,
+ JSObjectOps *ops, JSClass *clasp,
+ JSObject *obj);
+
+/*
+ * Generic type for an infallible JSObjectMap operation, used currently by
+ * JSObjectOps.destroyObjectMap.
+ */
+typedef void
+(* JS_DLL_CALLBACK JSObjectMapOp)(JSContext *cx, JSObjectMap *map);
+
+/*
+ * Look for id in obj and its prototype chain, returning false on error or
+ * exception, true on success. On success, return null in *propp if id was
+ * not found. If id was found, return the first object searching from obj
+ * along its prototype chain in which id names a direct property in *objp, and
+ * return a non-null, opaque property pointer in *propp.
+ *
+ * If JSLookupPropOp succeeds and returns with *propp non-null, that pointer
+ * may be passed as the prop parameter to a JSAttributesOp, as a short-cut
+ * that bypasses id re-lookup. In any case, a non-null *propp result after a
+ * successful lookup must be dropped via JSObjectOps.dropProperty.
+ *
+ * NB: successful return with non-null *propp means the implementation may
+ * have locked *objp and added a reference count associated with *propp, so
+ * callers should not risk deadlock by nesting or interleaving other lookups
+ * or any obj-bearing ops before dropping *propp.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id,
+ JSObject **objp, JSProperty **propp
+#if defined JS_THREADSAFE && defined DEBUG
+ , const char *file, uintN line
+#endif
+ );
+
+/*
+ * Define obj[id], a direct property of obj named id, having the given initial
+ * value, with the specified getter, setter, and attributes. If the propp out
+ * param is non-null, *propp on successful return contains an opaque property
+ * pointer usable as a speedup hint with JSAttributesOp. But note that propp
+ * may be null, indicating that the caller is not interested in recovering an
+ * opaque pointer to the newly-defined property.
+ *
+ * If propp is non-null and JSDefinePropOp succeeds, its caller must be sure
+ * to drop *propp using JSObjectOps.dropProperty in short order, just as with
+ * JSLookupPropOp.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSDefinePropOp)(JSContext *cx, JSObject *obj,
+ jsid id, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs, JSProperty **propp);
+
+/*
+ * Get, set, or delete obj[id], returning false on error or exception, true
+ * on success. If getting or setting, the new value is returned in *vp on
+ * success. If deleting without error, *vp will be JSVAL_FALSE if obj[id] is
+ * permanent, and JSVAL_TRUE if id named a direct property of obj that was in
+ * fact deleted, or if id names no direct property of obj (id could name a
+ * prototype property, or no property in obj or its prototype chain).
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id,
+ jsval *vp);
+
+/*
+ * Get or set attributes of the property obj[id]. Return false on error or
+ * exception, true with current attributes in *attrsp. If prop is non-null,
+ * it must come from the *propp out parameter of a prior JSDefinePropOp or
+ * JSLookupPropOp call.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSAttributesOp)(JSContext *cx, JSObject *obj, jsid id,
+ JSProperty *prop, uintN *attrsp);
+
+/*
+ * JSObjectOps.checkAccess type: check whether obj[id] may be accessed per
+ * mode, returning false on error/exception, true on success with obj[id]'s
+ * last-got value in *vp, and its attributes in *attrsp.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSCheckAccessIdOp)(JSContext *cx, JSObject *obj, jsid id,
+ JSAccessMode mode, jsval *vp,
+ uintN *attrsp);
+
+/*
+ * A generic type for functions mapping an object to another object, or null
+ * if an error or exception was thrown on cx. Used by JSObjectOps.thisObject
+ * at present.
+ */
+typedef JSObject *
+(* JS_DLL_CALLBACK JSObjectOp)(JSContext *cx, JSObject *obj);
+
+/*
+ * A generic type for functions taking a context, object, and property, with
+ * no return value. Used by JSObjectOps.dropProperty currently (see above,
+ * JSDefinePropOp and JSLookupPropOp, for the object-locking protocol in which
+ * dropProperty participates).
+ */
+typedef void
+(* JS_DLL_CALLBACK JSPropertyRefOp)(JSContext *cx, JSObject *obj,
+ JSProperty *prop);
+
+/*
+ * Function type for JSObjectOps.setProto and JSObjectOps.setParent. These
+ * hooks must check for cycles without deadlocking, and otherwise take special
+ * steps. See jsobj.c, js_SetProtoOrParent, for an example.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSSetObjectSlotOp)(JSContext *cx, JSObject *obj,
+ uint32 slot, JSObject *pobj);
+
+/*
+ * Get and set a required slot, one that should already have been allocated.
+ * These operations are infallible, so required slots must be pre-allocated,
+ * or implementations must suppress out-of-memory errors. The native ops
+ * (js_ObjectOps, see jsobj.c) access slots reserved by including a call to
+ * the JSCLASS_HAS_RESERVED_SLOTS(n) macro in the JSClass.flags initializer.
+ *
+ * NB: the slot parameter is a zero-based index into obj->slots[], unlike the
+ * index parameter to the JS_GetReservedSlot and JS_SetReservedSlot API entry
+ * points, which is a zero-based index into the JSCLASS_RESERVED_SLOTS(clasp)
+ * reserved slots that come after the initial well-known slots: proto, parent,
+ * class, and optionally, the private data slot.
+ */
+typedef jsval
+(* JS_DLL_CALLBACK JSGetRequiredSlotOp)(JSContext *cx, JSObject *obj,
+ uint32 slot);
+
+typedef void
+(* JS_DLL_CALLBACK JSSetRequiredSlotOp)(JSContext *cx, JSObject *obj,
+ uint32 slot, jsval v);
+
+/* Typedef for native functions called by the JS VM. */
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSNative)(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval);
+
+/* Callbacks and their arguments. */
+
+typedef enum JSGCStatus {
+ JSGC_BEGIN,
+ JSGC_END,
+ JSGC_MARK_END,
+ JSGC_FINALIZE_END
+} JSGCStatus;
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSGCCallback)(JSContext *cx, JSGCStatus status);
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSBranchCallback)(JSContext *cx, JSScript *script);
+
+typedef void
+(* JS_DLL_CALLBACK JSErrorReporter)(JSContext *cx, const char *message,
+ JSErrorReport *report);
+
+typedef struct JSErrorFormatString {
+ const char *format;
+ uintN argCount;
+} JSErrorFormatString;
+
+typedef const JSErrorFormatString *
+(* JS_DLL_CALLBACK JSErrorCallback)(void *userRef, const char *locale,
+ const uintN errorNumber);
+
+#ifdef va_start
+#define JS_ARGUMENT_FORMATTER_DEFINED 1
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSArgumentFormatter)(JSContext *cx, const char *format,
+ JSBool fromJS, jsval **vpp,
+ va_list *app);
+#endif
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSLocaleToUpperCase)(JSContext *cx, JSString *src,
+ jsval *rval);
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSLocaleToLowerCase)(JSContext *cx, JSString *src,
+ jsval *rval);
+
+typedef JSBool
+(* JS_DLL_CALLBACK JSLocaleCompare)(JSContext *cx,
+ JSString *src1, JSString *src2,
+ jsval *rval);
+
+/*
+ * Security protocol types.
+ */
+typedef struct JSPrincipals JSPrincipals;
+
+/*
+ * XDR-encode or -decode a principals instance, based on whether xdr->mode is
+ * JSXDR_ENCODE, in which case *principalsp should be encoded; or JSXDR_DECODE,
+ * in which case implementations must return a held (via JSPRINCIPALS_HOLD),
+ * non-null *principalsp out parameter. Return true on success, false on any
+ * error, which the implementation must have reported.
+ */
+typedef JSBool
+(* JS_DLL_CALLBACK JSPrincipalsTranscoder)(JSXDRState *xdr,
+ JSPrincipals **principalsp);
+
+/*
+ * Return a weak reference to the principals associated with obj, possibly via
+ * the immutable parent chain leading from obj to a top-level container (e.g.,
+ * a window object in the DOM level 0). If there are no principals associated
+ * with obj, return null. Therefore null does not mean an error was reported;
+ * in no event should an error be reported or an exception be thrown by this
+ * callback's implementation.
+ */
+typedef JSPrincipals *
+(* JS_DLL_CALLBACK JSObjectPrincipalsFinder)(JSContext *cx, JSObject *obj);
+
+JS_END_EXTERN_C
+
+#endif /* jspubtd_h___ */
diff --git a/src/dom/js/jsregexp.c b/src/dom/js/jsregexp.c
new file mode 100644
index 000000000..18ab92c35
--- /dev/null
+++ b/src/dom/js/jsregexp.c
@@ -0,0 +1,3773 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS regular expressions, after Perl.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsregexp.h"
+#include "jsscan.h"
+#include "jsstr.h"
+
+#ifdef XP_MAC
+#include <MacMemory.h>
+#endif
+
+#if JS_HAS_REGEXPS
+
+/* Note : contiguity of 'simple opcodes' is important for simpleMatch() */
+typedef enum REOp {
+ REOP_EMPTY = 0, /* match rest of input against rest of r.e. */
+ REOP_ALT = 1, /* alternative subexpressions in kid and next */
+ REOP_SIMPLE_START = 2, /* start of 'simple opcodes' */
+ REOP_BOL = 2, /* beginning of input (or line if multiline) */
+ REOP_EOL = 3, /* end of input (or line if multiline) */
+ REOP_WBDRY = 4, /* match "" at word boundary */
+ REOP_WNONBDRY = 5, /* match "" at word non-boundary */
+ REOP_DOT = 6, /* stands for any character */
+ REOP_DIGIT = 7, /* match a digit char: [0-9] */
+ REOP_NONDIGIT = 8, /* match a non-digit char: [^0-9] */
+ REOP_ALNUM = 9, /* match an alphanumeric char: [0-9a-z_A-Z] */
+ REOP_NONALNUM = 10, /* match a non-alphanumeric char: [^0-9a-z_A-Z] */
+ REOP_SPACE = 11, /* match a whitespace char */
+ REOP_NONSPACE = 12, /* match a non-whitespace char */
+ REOP_BACKREF = 13, /* back-reference (e.g., \1) to a parenthetical */
+ REOP_FLAT = 14, /* match a flat string */
+ REOP_FLAT1 = 15, /* match a single char */
+ REOP_FLATi = 16, /* case-independent REOP_FLAT */
+ REOP_FLAT1i = 17, /* case-independent REOP_FLAT1 */
+ REOP_UCFLAT1 = 18, /* single Unicode char */
+ REOP_UCFLAT1i = 19, /* case-independent REOP_UCFLAT1 */
+ REOP_UCFLAT = 20, /* flat Unicode string; len immediate counts chars */
+ REOP_UCFLATi = 21, /* case-independent REOP_UCFLAT */
+ REOP_CLASS = 22, /* character class with index */
+ REOP_NCLASS = 23, /* negated character class with index */
+ REOP_SIMPLE_END = 23, /* end of 'simple opcodes' */
+ REOP_QUANT = 25, /* quantified atom: atom{1,2} */
+ REOP_STAR = 26, /* zero or more occurrences of kid */
+ REOP_PLUS = 27, /* one or more occurrences of kid */
+ REOP_OPT = 28, /* optional subexpression in kid */
+ REOP_LPAREN = 29, /* left paren bytecode: kid is u.num'th sub-regexp */
+ REOP_RPAREN = 30, /* right paren bytecode */
+ REOP_JUMP = 31, /* for deoptimized closure loops */
+ REOP_DOTSTAR = 32, /* optimize .* to use a single opcode */
+ REOP_ANCHOR = 33, /* like .* but skips left context to unanchored r.e. */
+ REOP_EOLONLY = 34, /* $ not preceded by any pattern */
+ REOP_BACKREFi = 37, /* case-independent REOP_BACKREF */
+ REOP_LPARENNON = 41, /* non-capturing version of REOP_LPAREN */
+ REOP_ASSERT = 43, /* zero width positive lookahead assertion */
+ REOP_ASSERT_NOT = 44, /* zero width negative lookahead assertion */
+ REOP_ASSERTTEST = 45, /* sentinel at end of assertion child */
+ REOP_ASSERTNOTTEST = 46, /* sentinel at end of !assertion child */
+ REOP_MINIMALSTAR = 47, /* non-greedy version of * */
+ REOP_MINIMALPLUS = 48, /* non-greedy version of + */
+ REOP_MINIMALOPT = 49, /* non-greedy version of ? */
+ REOP_MINIMALQUANT = 50, /* non-greedy version of {} */
+ REOP_ENDCHILD = 51, /* sentinel at end of quantifier child */
+ REOP_REPEAT = 52, /* directs execution of greedy quantifier */
+ REOP_MINIMALREPEAT = 53, /* directs execution of non-greedy quantifier */
+ REOP_ALTPREREQ = 54, /* prerequisite for ALT, either of two chars */
+ REOP_ALTPREREQ2 = 55, /* prerequisite for ALT, a char or a class */
+ REOP_ENDALT = 56, /* end of final alternate */
+ REOP_CONCAT = 57, /* concatenation of terms (parse time only) */
+
+ REOP_END
+} REOp;
+
+#define REOP_IS_SIMPLE(op) (((op) >= REOP_SIMPLE_START) && ((op) <= REOP_SIMPLE_END))
+
+struct RENode {
+ REOp op; /* r.e. op bytecode */
+ RENode *next; /* next in concatenation order */
+ void *kid; /* first operand */
+ union {
+ void *kid2; /* second operand */
+ jsint num; /* could be a number */
+ jsint parenIndex; /* or a parenthesis index */
+ struct { /* or a quantifier range */
+ uint16 min;
+ uint16 max;
+ JSBool greedy;
+ } range;
+ struct { /* or a character class */
+ uint16 startIndex;
+ uint16 kidlen; /* length of string at kid, in jschars */
+ uint16 bmsize; /* bitmap size, based on max char code */
+ uint16 index; /* index into class list */
+ JSBool sense;
+ } ucclass;
+ struct { /* or a literal sequence */
+ jschar chr; /* of one character */
+ uint16 length; /* or many (via the kid) */
+ } flat;
+ struct {
+ RENode *kid2; /* second operand from ALT */
+ jschar ch1; /* match char for ALTPREREQ */
+ jschar ch2; /* ditto, or class index for ALTPREREQ2 */
+ } altprereq;
+ } u;
+};
+
+#define RE_IS_LETTER(c) ( ((c >= 'A') && (c <= 'Z')) || \
+ ((c >= 'a') && (c <= 'z')) )
+#define RE_IS_LINE_TERM(c) ( (c == '\n') || (c == '\r') || \
+ (c == LINE_SEPARATOR) || (c == PARA_SEPARATOR))
+
+#define CLASS_CACHE_SIZE (4)
+typedef struct CompilerState {
+ JSContext *context;
+ JSTokenStream *tokenStream; /* For reporting errors */
+ const jschar *cpbegin;
+ const jschar *cpend;
+ const jschar *cp;
+ uintN flags;
+ uint16 parenCount;
+ uint16 classCount; /* number of [] encountered */
+ size_t progLength; /* estimated bytecode length */
+ uintN treeDepth; /* maximum depth of parse tree */
+ RENode *result;
+ struct {
+ const jschar *start; /* small cache of class strings */
+ uint16 length; /* since they're often the same */
+ uint16 index;
+ } classCache[CLASS_CACHE_SIZE];
+} CompilerState;
+
+typedef struct RECapture {
+ int32 index; /* start of contents, -1 for empty */
+ uint16 length; /* length of capture */
+} RECapture;
+
+typedef struct REMatchState {
+ const jschar *cp;
+ RECapture parens[1]; /* first of 're->parenCount' captures,
+ * allocated at end of this struct.
+ */
+} REMatchState;
+
+struct REBackTrackData;
+
+typedef struct REProgState {
+ jsbytecode *continue_pc; /* current continuation data */
+ jsbytecode continue_op;
+ uint16 index; /* progress in text */
+ uintN parenSoFar; /* highest indexed paren started */
+ union {
+ struct {
+ uint16 min; /* current quantifier limits */
+ uint16 max;
+ } quantifier;
+ struct {
+ size_t top; /* backtrack stack state */
+ size_t sz;
+ } assertion;
+ } u;
+} REProgState;
+
+typedef struct REBackTrackData {
+ size_t sz; /* size of previous stack entry */
+ jsbytecode *backtrack_pc; /* where to backtrack to */
+ jsbytecode backtrack_op;
+ const jschar *cp; /* index in text of match at backtrack */
+ intN parenIndex; /* start index of saved paren contents */
+ uint16 parenCount; /* # of saved paren contents */
+ uint16 precedingStateTop; /* number of parent states */
+ /* saved parent states follow */
+ /* saved paren contents follow */
+} REBackTrackData;
+
+#define INITIAL_STATESTACK (100)
+#define INITIAL_BACKTRACK (8000)
+
+typedef struct REGlobalData {
+ JSContext *cx;
+ JSRegExp *regexp; /* the RE in execution */
+ JSBool ok; /* runtime error (out_of_memory only?) */
+ size_t start; /* offset to start at */
+ ptrdiff_t skipped; /* chars skipped anchoring this r.e. */
+ const jschar *cpbegin, *cpend; /* text base address and limit */
+
+ REProgState *stateStack; /* stack of state of current parents */
+ uint16 stateStackTop;
+ uint16 maxStateStack;
+
+ REBackTrackData *backTrackStack;/* stack of matched-so-far positions */
+ REBackTrackData *backTrackSP;
+ size_t maxBackTrack;
+ size_t cursz; /* size of current stack entry */
+
+ JSArenaPool pool; /* I don't understand but it's faster to
+ * use this than to malloc/free the three
+ * items that are allocated from this pool
+ */
+
+} REGlobalData;
+
+
+/*
+ * 1. If IgnoreCase is false, return ch.
+ * 2. Let u be ch converted to upper case as if by calling
+ * String.prototype.toUpperCase on the one-character string ch.
+ * 3. If u does not consist of a single character, return ch.
+ * 4. Let cu be u's character.
+ * 5. If ch's code point value is greater than or equal to decimal 128 and cu's
+ * code point value is less than decimal 128, then return ch.
+ * 6. Return cu.
+ */
+static jschar
+upcase(jschar ch)
+{
+ jschar cu = JS_TOUPPER(ch);
+ if ((ch >= 128) && (cu < 128)) return ch;
+ return cu;
+}
+
+static jschar
+downcase(jschar ch)
+{
+ jschar cl = JS_TOLOWER(ch);
+ if ((cl >= 128) && (ch < 128)) return ch;
+ return cl;
+}
+
+/* Construct and initialize an RENode, returning NULL for out-of-memory */
+static RENode *
+NewRENode(CompilerState *state, REOp op)
+{
+ JSContext *cx;
+ RENode *ren;
+
+ cx = state->context;
+ JS_ARENA_ALLOCATE_CAST(ren, RENode *, &cx->tempPool, sizeof *ren);
+ if (!ren) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ ren->op = op;
+ ren->next = NULL;
+ ren->kid = NULL;
+ return ren;
+}
+
+/*
+ * Validates and converts hex ascii value.
+ */
+static JSBool
+isASCIIHexDigit(jschar c, uintN *digit)
+{
+ uintN cv = c;
+
+ if (cv < '0')
+ return JS_FALSE;
+ if (cv <= '9') {
+ *digit = cv - '0';
+ return JS_TRUE;
+ }
+ cv |= 0x20;
+ if (cv >= 'a' && cv <= 'f') {
+ *digit = cv - 'a' + 10;
+ return JS_TRUE;
+ }
+ return JS_FALSE;
+}
+
+
+typedef struct {
+ REOp op;
+ const jschar *errPos;
+ uint16 parenIndex;
+} REOpData;
+
+
+/*
+ * Process the op against the two top operands, reducing them to a single
+ * operand in the penultimate slot. Update progLength and treeDepth.
+ */
+static JSBool
+processOp(CompilerState *state, REOpData *opData, RENode **operandStack, intN operandSP)
+{
+ RENode *result;
+
+ switch (opData->op) {
+ case REOP_ALT:
+ result = NewRENode(state, REOP_ALT);
+ if (!result)
+ return JS_FALSE;
+ result->kid = operandStack[operandSP - 2];
+ result->u.kid2 = operandStack[operandSP - 1];
+ operandStack[operandSP - 2] = result;
+ /*
+ * look at both alternates to see if there's a FLAT or a CLASS at
+ * the start of each. If so, use a prerequisite match
+ */
+ ++state->treeDepth;
+ if ((((RENode *)(result->kid))->op == REOP_FLAT)
+ && (((RENode *)(result->u.kid2))->op == REOP_FLAT)
+ && ((state->flags & JSREG_FOLD) == 0) ) {
+ result->op = REOP_ALTPREREQ;
+ result->u.altprereq.ch1
+ = ((RENode *)(result->kid))->u.flat.chr;
+ result->u.altprereq.ch2
+ = ((RENode *)(result->u.kid2))->u.flat.chr;
+ /* ALTPREREQ, <end>, uch1, uch2, <next>, ...,
+ JUMP, <end> ... ENDALT */
+ state->progLength += 13;
+ }
+ else
+ if ((((RENode *)(result->kid))->op == REOP_CLASS)
+ && (((RENode *)(result->kid))->u.ucclass.index < 256)
+ && (((RENode *)(result->u.kid2))->op == REOP_FLAT)
+ && ((state->flags & JSREG_FOLD) == 0) ) {
+ result->op = REOP_ALTPREREQ2;
+ result->u.altprereq.ch1
+ = ((RENode *)(result->u.kid2))->u.flat.chr;
+ result->u.altprereq.ch2
+ = ((RENode *)(result->kid))->u.ucclass.index;
+ /* ALTPREREQ2, <end>, uch1, uch2, <next>, ...,
+ JUMP, <end> ... ENDALT */
+ state->progLength += 13;
+ }
+ else
+ if ((((RENode *)(result->kid))->op == REOP_FLAT)
+ && (((RENode *)(result->u.kid2))->op == REOP_CLASS)
+ && (((RENode *)(result->u.kid2))->u.ucclass.index < 256)
+ && ((state->flags & JSREG_FOLD) == 0) ) {
+ result->op = REOP_ALTPREREQ2;
+ result->u.altprereq.ch1
+ = ((RENode *)(result->kid))->u.flat.chr;
+ result->u.altprereq.ch2
+ = ((RENode *)(result->u.kid2))->u.ucclass.index;
+ /* ALTPREREQ2, <end>, uch1, uch2, <next>, ...,
+ JUMP, <end> ... ENDALT */
+ state->progLength += 13;
+ }
+ else
+ /* ALT, <next>, ..., JUMP, <end> ... ENDALT */
+ state->progLength += 7;
+ break;
+ case REOP_CONCAT:
+ result = operandStack[operandSP - 2];
+ while (result->next)
+ result = result->next;
+ result->next = operandStack[operandSP - 1];
+ break;
+ case REOP_ASSERT:
+ case REOP_ASSERT_NOT:
+ case REOP_LPARENNON:
+ case REOP_LPAREN:
+ /* These should have been processed by a close paren. */
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_MISSING_PAREN, opData->errPos);
+ return JS_FALSE;
+ default:;
+ }
+ return JS_TRUE;
+}
+
+/*
+ * Parser forward declarations.
+ */
+static JSBool parseTerm(CompilerState *state);
+static JSBool parseQuantifier(CompilerState *state);
+
+/*
+ * Top-down regular expression grammar, based closely on Perl4.
+ *
+ * regexp: altern A regular expression is one or more
+ * altern '|' regexp alternatives separated by vertical bar.
+ */
+
+#define INITIAL_STACK_SIZE (128)
+static JSBool
+parseRegExp(CompilerState *state)
+{
+ uint16 parenIndex;
+ RENode *operand;
+ REOpData *operatorStack;
+ RENode **operandStack;
+ REOp op;
+ intN i;
+ JSBool result = JS_FALSE;
+
+ intN operatorSP = 0, operatorStackSize = INITIAL_STACK_SIZE;
+ intN operandSP = 0, operandStackSize = INITIAL_STACK_SIZE;
+
+ /* Watch out for empty regexp */
+ if (state->cp == state->cpend) {
+ state->result = NewRENode(state, REOP_EMPTY);
+ return (state->result != NULL);
+ }
+
+ operatorStack = (REOpData *)JS_malloc(state->context,
+ sizeof(REOpData) * operatorStackSize);
+ if (!operatorStack)
+ return JS_FALSE;
+
+ operandStack = (RENode **)JS_malloc(state->context,
+ sizeof(RENode *) * operandStackSize);
+ if (!operandStack)
+ goto out;
+
+
+ while (JS_TRUE) {
+ if (state->cp == state->cpend) {
+ /*
+ * If we are at the end of the regexp and we're short an operand,
+ * the regexp must have the form /x|/ or some such.
+ */
+ if (operatorSP == operandSP) {
+ operand = NewRENode(state, REOP_EMPTY);
+ if (!operand)
+ goto out;
+ goto pushOperand;
+ }
+ } else {
+ switch (*state->cp) {
+ /* balance '(' */
+ case '(': /* balance ')' */
+ ++state->cp;
+ if ((state->cp < state->cpend) && (*state->cp == '?')
+ && ( (state->cp[1] == '=')
+ || (state->cp[1] == '!')
+ || (state->cp[1] == ':') )) {
+ ++state->cp;
+ if (state->cp == state->cpend) {
+ js_ReportCompileErrorNumber(state->context,
+ state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_MISSING_PAREN);
+ goto out;
+ }
+ switch (*state->cp++) {
+ case '=':
+ op = REOP_ASSERT;
+ /* ASSERT, <next>, ... ASSERTTEST */
+ state->progLength += 4;
+ break;
+ case '!':
+ op = REOP_ASSERT_NOT;
+ /* ASSERTNOT, <next>, ... ASSERTNOTTEST */
+ state->progLength += 4;
+ break;
+ case ':':
+ op = REOP_LPARENNON;
+ break;
+ }
+ parenIndex = state->parenCount;
+ }
+ else {
+ op = REOP_LPAREN;
+ /* LPAREN, <index>, ... RPAREN, <index> */
+ state->progLength += 6;
+ parenIndex = state->parenCount++;
+ if (state->parenCount == 65535) {
+ js_ReportCompileErrorNumber(state->context,
+ state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_TOO_MANY_PARENS);
+ goto out;
+ }
+ }
+ goto pushOperator;
+ case ')':
+ /* If there's not a stacked open parenthesis, throw
+ * a syntax error.
+ */
+ for (i = operatorSP - 1; i >= 0; i--)
+ if ((operatorStack[i].op == REOP_ASSERT)
+ || (operatorStack[i].op == REOP_ASSERT_NOT)
+ || (operatorStack[i].op == REOP_LPARENNON)
+ || (operatorStack[i].op == REOP_LPAREN))
+ break;
+ if (i == -1) {
+ js_ReportCompileErrorNumber(state->context,
+ state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_UNMATCHED_RIGHT_PAREN);
+ goto out;
+ }
+ /* fall thru... */
+ case '|':
+ /* Expected an operand before these, so make an empty one */
+ operand = NewRENode(state, REOP_EMPTY);
+ if (!operand)
+ goto out;
+ goto pushOperand;
+ default:
+ if (!parseTerm(state))
+ goto out;
+ operand = state->result;
+pushOperand:
+ if (operandSP == operandStackSize) {
+ operandStackSize += operandStackSize;
+ operandStack =
+ (RENode **)JS_realloc(state->context, operandStack,
+ sizeof(RENode *) * operandStackSize);
+ if (!operandStack)
+ goto out;
+ }
+ operandStack[operandSP++] = operand;
+ break;
+ }
+ }
+ /* At the end; process remaining operators */
+restartOperator:
+ if (state->cp == state->cpend) {
+ while (operatorSP) {
+ --operatorSP;
+ if (!processOp(state, &operatorStack[operatorSP],
+ operandStack, operandSP))
+ goto out;
+ --operandSP;
+ }
+ JS_ASSERT(operandSP == 1);
+ state->result = operandStack[0];
+ result = JS_TRUE;
+ goto out;
+ }
+ switch (*state->cp) {
+ case '|':
+ /* Process any stacked 'concat' operators */
+ ++state->cp;
+ while (operatorSP
+ && (operatorStack[operatorSP - 1].op == REOP_CONCAT)) {
+ --operatorSP;
+ if (!processOp(state, &operatorStack[operatorSP],
+ operandStack, operandSP))
+ goto out;
+ --operandSP;
+ }
+ op = REOP_ALT;
+ goto pushOperator;
+
+ case ')':
+ /* If there's not a stacked open parenthesis,we
+ * accept the close as a flat.
+ */
+ for (i = operatorSP - 1; i >= 0; i--)
+ if ((operatorStack[i].op == REOP_ASSERT)
+ || (operatorStack[i].op == REOP_ASSERT_NOT)
+ || (operatorStack[i].op == REOP_LPARENNON)
+ || (operatorStack[i].op == REOP_LPAREN))
+ break;
+ if (i == -1) {
+ js_ReportCompileErrorNumber(state->context,
+ state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_UNMATCHED_RIGHT_PAREN);
+ goto out;
+ }
+ ++state->cp;
+ /* process everything on the stack until the open */
+ while (JS_TRUE) {
+ JS_ASSERT(operatorSP);
+ --operatorSP;
+ switch (operatorStack[operatorSP].op) {
+ case REOP_ASSERT:
+ case REOP_ASSERT_NOT:
+ case REOP_LPAREN:
+ operand = NewRENode(state, operatorStack[operatorSP].op);
+ if (!operand)
+ goto out;
+ operand->u.parenIndex
+ = operatorStack[operatorSP].parenIndex;
+ JS_ASSERT(operandSP);
+ operand->kid = operandStack[operandSP - 1];
+ operandStack[operandSP - 1] = operand;
+ ++state->treeDepth;
+ /* fall thru... */
+ case REOP_LPARENNON:
+ state->result = operandStack[operandSP - 1];
+ if (!parseQuantifier(state))
+ goto out;
+ operandStack[operandSP - 1] = state->result;
+ goto restartOperator;
+ default:
+ if (!processOp(state, &operatorStack[operatorSP],
+ operandStack, operandSP))
+ goto out;
+ --operandSP;
+ break;
+ }
+ }
+ break;
+ default:
+ /* Anything else is the start of the next term */
+ op = REOP_CONCAT;
+pushOperator:
+ if (operatorSP == operatorStackSize) {
+ operatorStackSize += operatorStackSize;
+ operatorStack =
+ (REOpData *)JS_realloc(state->context, operatorStack,
+ sizeof(REOpData) * operatorStackSize);
+ if (!operatorStack)
+ goto out;
+ }
+ operatorStack[operatorSP].op = op;
+ operatorStack[operatorSP].errPos = state->cp;
+ operatorStack[operatorSP++].parenIndex = parenIndex;
+ break;
+ }
+ }
+out:
+ if (operatorStack)
+ JS_free(state->context, operatorStack);
+ if (operandStack)
+ JS_free(state->context, operandStack);
+ return result;
+}
+
+/*
+ * Extract and return a decimal value at state->cp, the
+ * initial character 'c' has already been read.
+ */
+static intN
+getDecimalValue(jschar c, CompilerState *state)
+{
+ intN value = JS7_UNDEC(c);
+ while (state->cp < state->cpend) {
+ c = *state->cp;
+ if (!JS7_ISDEC(c))
+ break;
+ value = (10 * value) + JS7_UNDEC(c);
+ ++state->cp;
+ }
+ return value;
+}
+
+/*
+ * Calculate the total size of the bitmap required for a class expression.
+ */
+static JSBool
+calculateBitmapSize(CompilerState *state, RENode *target, const jschar *src,
+ const jschar *end)
+{
+ jschar rangeStart, c;
+ uintN n, digit, nDigits, i;
+ uintN max = 0;
+ JSBool inRange = JS_FALSE;
+
+ target->u.ucclass.bmsize = 0;
+ target->u.ucclass.sense = JS_TRUE;
+
+ if (src == end)
+ return JS_TRUE;
+
+ if (*src == '^') {
+ ++src;
+ target->u.ucclass.sense = JS_FALSE;
+ }
+
+ while (src != end) {
+ uintN localMax = 0;
+ switch (*src) {
+ case '\\':
+ ++src;
+ c = *src++;
+ switch (c) {
+ case 'b':
+ localMax = 0x8;
+ break;
+ case 'f':
+ localMax = 0xC;
+ break;
+ case 'n':
+ localMax = 0xA;
+ break;
+ case 'r':
+ localMax = 0xD;
+ break;
+ case 't':
+ localMax = 0x9;
+ break;
+ case 'v':
+ localMax = 0xB;
+ break;
+ case 'c':
+ if (((src + 1) < end) && RE_IS_LETTER(src[1]))
+ localMax = (jschar)(*src++ & 0x1F);
+ else
+ localMax = '\\';
+ break;
+ case 'x':
+ nDigits = 2;
+ goto lexHex;
+ case 'u':
+ nDigits = 4;
+lexHex:
+ n = 0;
+ for (i = 0; (i < nDigits) && (src < end); i++) {
+ c = *src++;
+ if (!isASCIIHexDigit(c, &digit)) {
+ /*
+ * Back off to accepting the original
+ *'\' as a literal.
+ */
+ src -= (i + 1);
+ n = '\\';
+ break;
+ }
+ n = (n << 4) | digit;
+ }
+ localMax = n;
+ break;
+ case 'd':
+ if (inRange) {
+ JS_ReportErrorNumber(state->context,
+ js_GetErrorMessage, NULL,
+ JSMSG_BAD_CLASS_RANGE);
+ return JS_FALSE;
+ }
+ localMax = '9';
+ break;
+ case 'D':
+ case 's':
+ case 'S':
+ case 'w':
+ case 'W':
+ if (inRange) {
+ JS_ReportErrorNumber(state->context,
+ js_GetErrorMessage, NULL,
+ JSMSG_BAD_CLASS_RANGE);
+ return JS_FALSE;
+ }
+ target->u.ucclass.bmsize = 65535;
+ return JS_TRUE;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ /*
+ * This is a non-ECMA extension - decimal escapes (in this
+ * case, octal!) are supposed to be an error inside class
+ * ranges, but supported here for backwards compatibility.
+ *
+ */
+ n = JS7_UNDEC(c);
+ c = *src;
+ if ('0' <= c && c <= '7') {
+ src++;
+ n = 8 * n + JS7_UNDEC(c);
+ c = *src;
+ if ('0' <= c && c <= '7') {
+ src++;
+ i = 8 * n + JS7_UNDEC(c);
+ if (i <= 0377)
+ n = i;
+ else
+ src--;
+ }
+ }
+ localMax = n;
+ break;
+
+ default:
+ localMax = c;
+ break;
+ }
+ break;
+ default:
+ localMax = *src++;
+ break;
+ }
+ if (inRange) {
+ if (rangeStart > localMax) {
+ JS_ReportErrorNumber(state->context,
+ js_GetErrorMessage, NULL,
+ JSMSG_BAD_CLASS_RANGE);
+ return JS_FALSE;
+ }
+ inRange = JS_FALSE;
+ }
+ else {
+ if (src < (end - 1)) {
+ if (*src == '-') {
+ ++src;
+ inRange = JS_TRUE;
+ rangeStart = (jschar)localMax;
+ continue;
+ }
+ }
+ }
+ if (state->flags & JSREG_FOLD) {
+ c = JS_MAX(upcase((jschar)localMax), downcase((jschar)localMax));
+ if (c > localMax)
+ localMax = c;
+ }
+ if (localMax > max)
+ max = localMax;
+ }
+ target->u.ucclass.bmsize = max;
+ return JS_TRUE;
+}
+
+/*
+ * item: assertion An item is either an assertion or
+ * quantatom a quantified atom.
+ *
+ * assertion: '^' Assertions match beginning of string
+ * (or line if the class static property
+ * RegExp.multiline is true).
+ * '$' End of string (or line if the class
+ * static property RegExp.multiline is
+ * true).
+ * '\b' Word boundary (between \w and \W).
+ * '\B' Word non-boundary.
+ *
+ * quantatom: atom An unquantified atom.
+ * quantatom '{' n ',' m '}'
+ * Atom must occur between n and m times.
+ * quantatom '{' n ',' '}' Atom must occur at least n times.
+ * quantatom '{' n '}' Atom must occur exactly n times.
+ * quantatom '*' Zero or more times (same as {0,}).
+ * quantatom '+' One or more times (same as {1,}).
+ * quantatom '?' Zero or one time (same as {0,1}).
+ *
+ * any of which can be optionally followed by '?' for ungreedy
+ *
+ * atom: '(' regexp ')' A parenthesized regexp (what matched
+ * can be addressed using a backreference,
+ * see '\' n below).
+ * '.' Matches any char except '\n'.
+ * '[' classlist ']' A character class.
+ * '[' '^' classlist ']' A negated character class.
+ * '\f' Form Feed.
+ * '\n' Newline (Line Feed).
+ * '\r' Carriage Return.
+ * '\t' Horizontal Tab.
+ * '\v' Vertical Tab.
+ * '\d' A digit (same as [0-9]).
+ * '\D' A non-digit.
+ * '\w' A word character, [0-9a-z_A-Z].
+ * '\W' A non-word character.
+ * '\s' A whitespace character, [ \b\f\n\r\t\v].
+ * '\S' A non-whitespace character.
+ * '\' n A backreference to the nth (n decimal
+ * and positive) parenthesized expression.
+ * '\' octal An octal escape sequence (octal must be
+ * two or three digits long, unless it is
+ * 0 for the null character).
+ * '\x' hex A hex escape (hex must be two digits).
+ * '\u' unicode A unicode escape (must be four digits).
+ * '\c' ctrl A control character, ctrl is a letter.
+ * '\' literalatomchar Any character except one of the above
+ * that follow '\' in an atom.
+ * otheratomchar Any character not first among the other
+ * atom right-hand sides.
+ */
+static JSBool
+parseTerm(CompilerState *state)
+{
+ jschar c = *state->cp++;
+ uintN nDigits;
+ uintN num, tmp, n, i;
+ const jschar *termStart;
+ JSBool foundCachedCopy;
+
+ switch (c) {
+ /* assertions and atoms */
+ case '^':
+ state->result = NewRENode(state, REOP_BOL);
+ if (!state->result)
+ return JS_FALSE;
+ state->progLength++;
+ return JS_TRUE;
+ case '$':
+ state->result = NewRENode(state, REOP_EOL);
+ if (!state->result)
+ return JS_FALSE;
+ state->progLength++;
+ return JS_TRUE;
+ case '\\':
+ if (state->cp >= state->cpend) {
+ /* a trailing '\' is an error */
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_TRAILING_SLASH);
+ return JS_FALSE;
+ }
+ c = *state->cp++;
+ switch (c) {
+ /* assertion escapes */
+ case 'b' :
+ state->result = NewRENode(state, REOP_WBDRY);
+ if (!state->result)
+ return JS_FALSE;
+ state->progLength++;
+ return JS_TRUE;
+ case 'B':
+ state->result = NewRENode(state, REOP_WNONBDRY);
+ if (!state->result)
+ return JS_FALSE;
+ state->progLength++;
+ return JS_TRUE;
+ /* Decimal escape */
+ case '0':
+ if (JS_HAS_STRICT_OPTION(state->context))
+ c = 0;
+ else {
+ doOctal:
+ num = 0;
+ while (state->cp < state->cpend) {
+ if ('0' <= (c = *state->cp) && c <= '7') {
+ state->cp++;
+ tmp = 8 * num + (uintN)JS7_UNDEC(c);
+ if (tmp > 0377)
+ break;
+ num = tmp;
+ }
+ else
+ break;
+ }
+ c = (jschar)(num);
+ }
+ doFlat:
+ state->result = NewRENode(state, REOP_FLAT);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.flat.chr = c;
+ state->result->u.flat.length = 1;
+ state->progLength += 3;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ termStart = state->cp - 1;
+ num = (uintN)getDecimalValue(c, state);
+ if (num > 9 &&
+ num > state->parenCount &&
+ !JS_HAS_STRICT_OPTION(state->context)) {
+ state->cp = termStart;
+ goto doOctal;
+ }
+ state->result = NewRENode(state, REOP_BACKREF);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.parenIndex = num - 1;
+ state->progLength += 3;
+ break;
+ /* Control escape */
+ case 'f':
+ c = 0xC;
+ goto doFlat;
+ case 'n':
+ c = 0xA;
+ goto doFlat;
+ case 'r':
+ c = 0xD;
+ goto doFlat;
+ case 't':
+ c = 0x9;
+ goto doFlat;
+ case 'v':
+ c = 0xB;
+ goto doFlat;
+ /* Control letter */
+ case 'c':
+ if (((state->cp + 1) < state->cpend) &&
+ RE_IS_LETTER(state->cp[1]))
+ c = (jschar)(*state->cp++ & 0x1F);
+ else {
+ /* back off to accepting the original '\' as a literal */
+ --state->cp;
+ c = '\\';
+ }
+ goto doFlat;
+ /* HexEscapeSequence */
+ case 'x':
+ nDigits = 2;
+ goto lexHex;
+ /* UnicodeEscapeSequence */
+ case 'u':
+ nDigits = 4;
+lexHex:
+ n = 0;
+ for (i = 0; (i < nDigits)
+ && (state->cp < state->cpend); i++) {
+ uintN digit;
+ c = *state->cp++;
+ if (!isASCIIHexDigit(c, &digit)) {
+ /*
+ * back off to accepting the original
+ * 'u' or 'x' as a literal
+ */
+ state->cp -= (i + 2);
+ n = *state->cp++;
+ break;
+ }
+ n = (n << 4) | digit;
+ }
+ c = (jschar)(n);
+ goto doFlat;
+ /* Character class escapes */
+ case 'd':
+ state->result = NewRENode(state, REOP_DIGIT);
+doSimple:
+ if (!state->result)
+ return JS_FALSE;
+ state->progLength++;
+ break;
+ case 'D':
+ state->result = NewRENode(state, REOP_NONDIGIT);
+ goto doSimple;
+ case 's':
+ state->result = NewRENode(state, REOP_SPACE);
+ goto doSimple;
+ case 'S':
+ state->result = NewRENode(state, REOP_NONSPACE);
+ goto doSimple;
+ case 'w':
+ state->result = NewRENode(state, REOP_ALNUM);
+ goto doSimple;
+ case 'W':
+ state->result = NewRENode(state, REOP_NONALNUM);
+ goto doSimple;
+ /* IdentityEscape */
+ default:
+ state->result = NewRENode(state, REOP_FLAT);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.flat.chr = c;
+ state->result->u.flat.length = 1;
+ state->result->kid = (void *)(state->cp - 1);
+ state->progLength += 3;
+ break;
+ }
+ break;
+ case '[':
+ state->result = NewRENode(state, REOP_CLASS);
+ if (!state->result)
+ return JS_FALSE;
+ termStart = state->cp;
+ state->result->u.ucclass.startIndex = termStart - state->cpbegin;
+ while (JS_TRUE) {
+ if (state->cp == state->cpend) {
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_UNTERM_CLASS, termStart);
+ return JS_FALSE;
+ }
+ if (*state->cp == '\\')
+ state->cp++;
+ else {
+ if (*state->cp == ']') {
+ state->result->u.ucclass.kidlen = state->cp - termStart;
+ break;
+ }
+ }
+ state->cp++;
+ }
+ foundCachedCopy = JS_FALSE;
+ for (i = 0; i < CLASS_CACHE_SIZE; i++) {
+ if (state->classCache[i].start) {
+ if (state->classCache[i].length == state->result->u.ucclass.kidlen) {
+ foundCachedCopy = JS_TRUE;
+ for (n = 0; n < state->classCache[i].length; n++) {
+ if (state->classCache[i].start[n] != termStart[n]) {
+ foundCachedCopy = JS_FALSE;
+ break;
+ }
+ }
+ if (foundCachedCopy) {
+ state->result->u.ucclass.index = state->classCache[i].index;
+ break;
+ }
+ }
+ }
+ else {
+ state->classCache[i].start = termStart;
+ state->classCache[i].length = state->result->u.ucclass.kidlen;
+ state->classCache[i].index = state->classCount;
+ break;
+ }
+ }
+ if (!foundCachedCopy)
+ state->result->u.ucclass.index = state->classCount++;
+ /*
+ * Call calculateBitmapSize now as we want any errors it finds
+ * to be reported during the parse phase, not at execution.
+ */
+ if (!calculateBitmapSize(state, state->result, termStart, state->cp++))
+ return JS_FALSE;
+ state->progLength += 3; /* CLASS, <index> */
+ break;
+
+ case '.':
+ state->result = NewRENode(state, REOP_DOT);
+ goto doSimple;
+ case '*':
+ case '+':
+ case '?':
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_BAD_QUANTIFIER, state->cp - 1);
+ return JS_FALSE;
+#if 0
+ case '{': /* balance '}' */
+ /* Treat left-curly in a non-quantifier context as an error only
+ * if it's followed immediately by a decimal digit.
+ * This is an Perl extension.
+ */
+ if ((state->cp != state->cpend) && JS7_ISDEC(*state->cp)) {
+ js_ReportCompileErrorNumber(state->context, state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ JSMSG_BAD_QUANTIFIER, state->cp - 1);
+ return JS_FALSE;
+ }
+ /* fall thru... */
+#endif
+ default:
+ state->result = NewRENode(state, REOP_FLAT);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.flat.chr = c;
+ state->result->u.flat.length = 1;
+ state->result->kid = (void *)(state->cp - 1);
+ state->progLength += 3;
+ break;
+ }
+ return parseQuantifier(state);
+}
+
+static JSBool
+parseQuantifier(CompilerState *state)
+{
+ RENode *term;
+ term = state->result;
+ if (state->cp < state->cpend) {
+ switch (*state->cp) {
+ case '+':
+ state->result = NewRENode(state, REOP_QUANT);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.range.min = 1;
+ state->result->u.range.max = -1;
+ /* <PLUS>, <next> ... <ENDCHILD> */
+ state->progLength += 4;
+ goto quantifier;
+ case '*':
+ state->result = NewRENode(state, REOP_QUANT);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.range.min = 0;
+ state->result->u.range.max = -1;
+ /* <STAR>, <next> ... <ENDCHILD> */
+ state->progLength += 4;
+ goto quantifier;
+ case '?':
+ state->result = NewRENode(state, REOP_QUANT);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.range.min = 0;
+ state->result->u.range.max = 1;
+ /* <OPT>, <next> ... <ENDCHILD> */
+ state->progLength += 4;
+ goto quantifier;
+ case '{': /* balance '}' */
+ {
+ intN err;
+ intN min = 0;
+ intN max = -1;
+ jschar c;
+ const jschar *errp = state->cp++;
+
+ c = *state->cp;
+ if (JS7_ISDEC(c)) {
+ ++state->cp;
+ min = getDecimalValue(c, state);
+ c = *state->cp;
+
+ if ((min + 1) >> 16) {
+ err = JSMSG_MIN_TOO_BIG;
+ goto quantError;
+ }
+ if (c == ',') {
+ c = *++state->cp;
+ if (JS7_ISDEC(c)) {
+ ++state->cp;
+ max = getDecimalValue(c, state);
+ c = *state->cp;
+ if ((max + 1) >> 16) {
+ err = JSMSG_MAX_TOO_BIG;
+ goto quantError;
+ }
+ if (min > max) {
+ err = JSMSG_OUT_OF_ORDER;
+ goto quantError;
+ }
+ }
+ }
+ else {
+ max = min;
+ }
+ if (c == '}') {
+ state->result = NewRENode(state, REOP_QUANT);
+ if (!state->result)
+ return JS_FALSE;
+ state->result->u.range.min = min;
+ state->result->u.range.max = max;
+ /* QUANT, <min>, <max>, <next> ... <ENDCHILD> */
+ state->progLength += 8;
+ goto quantifier;
+ }
+ }
+ state->cp = errp;
+ return JS_TRUE;
+quantError:
+ js_ReportCompileErrorNumber(state->context,
+ state->tokenStream,
+ NULL, JSREPORT_ERROR,
+ err, errp);
+ return JS_FALSE;
+ }
+ }
+ }
+ return JS_TRUE;
+
+quantifier:
+ ++state->treeDepth;
+ ++state->cp;
+ state->result->kid = term;
+ if ((state->cp < state->cpend) && (*state->cp == '?')) {
+ ++state->cp;
+ state->result->u.range.greedy = JS_FALSE;
+ }
+ else
+ state->result->u.range.greedy = JS_TRUE;
+ return JS_TRUE;
+}
+
+#define CHECK_OFFSET(diff) (JS_ASSERT(((diff) >= -32768) && ((diff) <= 32767)))
+#define SET_OFFSET(pc,off) ((pc)[0] = JUMP_OFFSET_HI(off), \
+ (pc)[1] = JUMP_OFFSET_LO(off))
+#define GET_OFFSET(pc) ((int16)(((pc)[0] << 8) | (pc)[1]))
+#define OFFSET_LEN (2)
+#define GET_ARG(pc) GET_OFFSET(pc)
+#define SET_ARG(pc,arg) SET_OFFSET(pc,arg)
+#define ARG_LEN OFFSET_LEN
+
+/*
+ * Recursively generate bytecode for the tree rooted at t. Iteratively.
+ */
+
+typedef struct {
+ RENode *nextAlt;
+ jsbytecode *nextAltFixup, *nextTermFixup, *endTermFixup;
+ RENode *continueNode;
+ REOp continueOp;
+} EmitStateStackEntry;
+
+static jsbytecode *
+emitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
+ jsbytecode *pc, RENode *t)
+{
+ ptrdiff_t diff;
+ RECharSet *charSet;
+ EmitStateStackEntry *emitStateSP, *emitStateStack = NULL;
+ REOp op;
+
+ if (treeDepth) {
+ emitStateStack =
+ (EmitStateStackEntry *)JS_malloc(state->context,
+ sizeof(EmitStateStackEntry)
+ * treeDepth);
+ if (!emitStateStack)
+ return NULL;
+ }
+ emitStateSP = emitStateStack;
+ op = t->op;
+
+ while (JS_TRUE) {
+ *pc++ = op;
+ switch (op) {
+ case REOP_EMPTY:
+ --pc;
+ break;
+
+ case REOP_ALTPREREQ2:
+ case REOP_ALTPREREQ:
+ JS_ASSERT(emitStateSP);
+ emitStateSP->endTermFixup = pc;
+ pc += OFFSET_LEN;
+ SET_ARG(pc, t->u.altprereq.ch1);
+ pc += ARG_LEN;
+ SET_ARG(pc, t->u.altprereq.ch2);
+ pc += ARG_LEN;
+
+ emitStateSP->nextAltFixup = pc; /* address of next alternate */
+ pc += OFFSET_LEN;
+
+ emitStateSP->continueNode = t;
+ emitStateSP->continueOp = REOP_JUMP;
+ ++emitStateSP;
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+ t = (RENode *)(t->kid);
+ op = t->op;
+ continue;
+
+ case REOP_JUMP:
+ emitStateSP->nextTermFixup = pc; /* address of following term */
+ pc += OFFSET_LEN;
+ diff = pc - emitStateSP->nextAltFixup;
+ CHECK_OFFSET(diff);
+ SET_OFFSET(emitStateSP->nextAltFixup, diff);
+ emitStateSP->continueOp = REOP_ENDALT;
+ ++emitStateSP;
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+ t = (RENode *)(t->u.kid2);
+ op = t->op;
+ continue;
+
+ case REOP_ENDALT:
+ diff = pc - emitStateSP->nextTermFixup;
+ CHECK_OFFSET(diff);
+ SET_OFFSET(emitStateSP->nextTermFixup, diff);
+ if (t->op != REOP_ALT) {
+ diff = pc - emitStateSP->endTermFixup;
+ CHECK_OFFSET(diff);
+ SET_OFFSET(emitStateSP->endTermFixup, diff);
+ }
+ break;
+
+ case REOP_ALT:
+ JS_ASSERT(emitStateSP);
+ emitStateSP->nextAltFixup = pc; /* address of pointer to next alternate */
+ pc += OFFSET_LEN;
+ emitStateSP->continueNode = t;
+ emitStateSP->continueOp = REOP_JUMP;
+ ++emitStateSP;
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+ t = (RENode *)(t->kid);
+ op = t->op;
+ continue;
+
+ case REOP_FLAT:
+ /*
+ * Consecutize FLAT's if possible.
+ */
+ if (t->kid) {
+ while (t->next && (t->next->op == REOP_FLAT)
+ && (((jschar*)(t->kid) + t->u.flat.length)
+ == (jschar*)(t->next->kid))) {
+ t->u.flat.length += t->next->u.flat.length;
+ t->next = t->next->next;
+ }
+ }
+ if (t->kid && (t->u.flat.length > 1)) {
+ if (state->flags & JSREG_FOLD)
+ pc[-1] = REOP_FLATi;
+ else
+ pc[-1] = REOP_FLAT;
+ SET_ARG(pc, (jschar *)(t->kid) - state->cpbegin);
+ pc += ARG_LEN;
+ SET_ARG(pc, t->u.flat.length);
+ pc += ARG_LEN;
+ }
+ else {
+ if (t->u.flat.chr < 256) {
+ if (state->flags & JSREG_FOLD)
+ pc[-1] = REOP_FLAT1i;
+ else
+ pc[-1] = REOP_FLAT1;
+ *pc++ = (jsbytecode)(t->u.flat.chr);
+ }
+ else {
+ if (state->flags & JSREG_FOLD)
+ pc[-1] = REOP_UCFLAT1i;
+ else
+ pc[-1] = REOP_UCFLAT1;
+ SET_ARG(pc, t->u.flat.chr);
+ pc += ARG_LEN;
+ }
+ }
+ break;
+
+ case REOP_LPAREN:
+ JS_ASSERT(emitStateSP);
+ SET_ARG(pc, t->u.parenIndex);
+ pc += ARG_LEN;
+ emitStateSP->continueNode = t;
+ emitStateSP->continueOp = REOP_RPAREN;
+ ++emitStateSP;
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+ t = (RENode *)(t->kid);
+ op = t->op;
+ continue;
+ case REOP_RPAREN:
+ SET_ARG(pc, t->u.parenIndex);
+ pc += ARG_LEN;
+ break;
+
+ case REOP_BACKREF:
+ SET_ARG(pc, t->u.parenIndex);
+ pc += ARG_LEN;
+ break;
+ case REOP_ASSERT:
+ JS_ASSERT(emitStateSP);
+ emitStateSP->nextTermFixup = pc;
+ pc += OFFSET_LEN;
+ emitStateSP->continueNode = t;
+ emitStateSP->continueOp = REOP_ASSERTTEST;
+ ++emitStateSP;
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+ t = (RENode *)(t->kid);
+ op = t->op;
+ continue;
+ case REOP_ASSERTTEST:
+ case REOP_ASSERTNOTTEST:
+ diff = pc - emitStateSP->nextTermFixup;
+ CHECK_OFFSET(diff);
+ SET_OFFSET(emitStateSP->nextTermFixup, diff);
+ break;
+ case REOP_ASSERT_NOT:
+ JS_ASSERT(emitStateSP);
+ emitStateSP->nextTermFixup = pc;
+ pc += OFFSET_LEN;
+ emitStateSP->continueNode = t;
+ emitStateSP->continueOp = REOP_ASSERTNOTTEST;
+ ++emitStateSP;
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+ t = (RENode *)(t->kid);
+ op = t->op;
+ continue;
+ case REOP_QUANT:
+ JS_ASSERT(emitStateSP);
+ if ((t->u.range.min == 0) && (t->u.range.max == (uint16)(-1)))
+ pc[-1] = (t->u.range.greedy) ? REOP_STAR : REOP_MINIMALSTAR;
+ else
+ if ((t->u.range.min == 0) && (t->u.range.max == 1))
+ pc[-1] = (t->u.range.greedy) ? REOP_OPT : REOP_MINIMALOPT;
+ else
+ if ((t->u.range.min == 1) && (t->u.range.max == (uint16)(-1)))
+ pc[-1] = (t->u.range.greedy) ? REOP_PLUS : REOP_MINIMALPLUS;
+ else {
+ if (!t->u.range.greedy) pc[-1] = REOP_MINIMALQUANT;
+ SET_ARG(pc, t->u.range.min);
+ pc += ARG_LEN;
+ SET_ARG(pc, t->u.range.max);
+ pc += ARG_LEN;
+ }
+ emitStateSP->nextTermFixup = pc;
+ pc += OFFSET_LEN;
+ emitStateSP->continueNode = t;
+ emitStateSP->continueOp = REOP_ENDCHILD;
+ ++emitStateSP;
+ JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+ t = (RENode *)(t->kid);
+ op = t->op;
+ continue;
+ case REOP_ENDCHILD:
+ diff = pc - emitStateSP->nextTermFixup;
+ CHECK_OFFSET(diff);
+ SET_OFFSET(emitStateSP->nextTermFixup, diff);
+ break;
+ case REOP_CLASS:
+ if (!t->u.ucclass.sense)
+ pc[-1] = REOP_NCLASS;
+ SET_ARG(pc, t->u.ucclass.index);
+ pc += ARG_LEN;
+ charSet = &re->classList[t->u.ucclass.index];
+ charSet->converted = JS_FALSE;
+ charSet->length = t->u.ucclass.bmsize;
+ charSet->u.src.startIndex = t->u.ucclass.startIndex;
+ charSet->u.src.length = t->u.ucclass.kidlen;
+ charSet->sense = t->u.ucclass.sense;
+ break;
+ default:
+ break;
+ }
+ t = t->next;
+ if (t == NULL) {
+ if (emitStateSP == emitStateStack)
+ break;
+ --emitStateSP;
+ t = emitStateSP->continueNode;
+ op = emitStateSP->continueOp;
+ }
+ else
+ op = t->op;
+ }
+ if (emitStateStack)
+ JS_free(state->context, emitStateStack);
+ return pc;
+}
+
+
+JSRegExp *
+js_NewRegExp(JSContext *cx, JSTokenStream *ts,
+ JSString *str, uintN flags, JSBool flat)
+{
+ JSRegExp *re;
+ void *mark;
+ CompilerState state;
+ size_t resize;
+ jsbytecode *endPC;
+ uint32 i;
+ size_t len;
+
+ re = NULL;
+ mark = JS_ARENA_MARK(&cx->tempPool);
+
+ state.context = cx;
+ state.tokenStream = ts;
+ state.cpbegin = state.cp = JSSTRING_CHARS(str);
+ state.cpend = state.cp + JSSTRING_LENGTH(str);
+ state.flags = flags;
+ state.parenCount = 0;
+ state.classCount = 0;
+ state.progLength = 0;
+ state.treeDepth = 0;
+ for (i = 0; i < CLASS_CACHE_SIZE; i++)
+ state.classCache[i].start = NULL;
+
+ len = JSSTRING_LENGTH(str);
+
+ if (len != 0 && flat) {
+ state.result = NewRENode(&state, REOP_FLAT);
+ state.result->u.flat.chr = *state.cpbegin;
+ state.result->u.flat.length = JSSTRING_LENGTH(str);
+ state.result->kid = (void *)(state.cpbegin);
+ state.progLength += 5;
+ }
+ else {
+ if (!parseRegExp(&state))
+ goto out;
+ }
+ resize = sizeof *re + state.progLength + 1;
+ re = (JSRegExp *) JS_malloc(cx, JS_ROUNDUP(resize, sizeof(jsword)));
+ if (!re)
+ goto out;
+
+ re->classCount = state.classCount;
+ if (state.classCount) {
+ re->classList = (RECharSet *)JS_malloc(cx, sizeof(RECharSet)
+ * state.classCount);
+ if (!re->classList)
+ goto out;
+ }
+ else
+ re->classList = NULL;
+ endPC = emitREBytecode(&state, re, state.treeDepth, re->program, state.result);
+ if (!endPC) {
+ re = NULL;
+ goto out;
+ }
+ *endPC++ = REOP_END;
+ JS_ASSERT(endPC <= (re->program + (state.progLength + 1)));
+
+ re->nrefs = 1;
+ re->parenCount = state.parenCount;
+ re->flags = flags;
+ re->source = str;
+
+out:
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return re;
+}
+
+JSRegExp *
+js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts,
+ JSString *str, JSString *opt, JSBool flat)
+{
+ uintN flags;
+ jschar *s;
+ size_t i, n;
+ char charBuf[2];
+
+ flags = 0;
+ if (opt) {
+ s = JSSTRING_CHARS(opt);
+ for (i = 0, n = JSSTRING_LENGTH(opt); i < n; i++) {
+ switch (s[i]) {
+ case 'g':
+ flags |= JSREG_GLOB;
+ break;
+ case 'i':
+ flags |= JSREG_FOLD;
+ break;
+ case 'm':
+ flags |= JSREG_MULTILINE;
+ break;
+ default:
+ charBuf[0] = (char)s[i];
+ charBuf[1] = '\0';
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_FLAG, charBuf);
+ return NULL;
+ }
+ }
+ }
+ return js_NewRegExp(cx, ts, str, flags, flat);
+}
+
+
+#define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs)
+#define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re)
+
+/*
+ * Save the current state of the match - the position in the input
+ * text as well as the position in the bytecode. The state of any
+ * parent expressions is also saved (preceding state).
+ * Contents of parenCount parentheses from parenIndex are also saved.
+ */
+static REBackTrackData *
+pushBackTrackState(REGlobalData *gData, REOp op,
+ jsbytecode *target, REMatchState *x, const jschar *cp,
+ intN parenIndex, intN parenCount)
+{
+ intN i;
+ REBackTrackData *result
+ = (REBackTrackData *)((char *)(gData->backTrackSP) + gData->cursz);
+
+ size_t sz = sizeof(REBackTrackData)
+ + gData->stateStackTop * sizeof(REProgState)
+ + parenCount * sizeof(RECapture);
+
+
+ if (((char *)result + sz)
+ > (char *)gData->backTrackStack + gData->maxBackTrack) {
+ ptrdiff_t offset = (char *)result - (char *)gData->backTrackStack;
+ gData->backTrackStack
+ = (REBackTrackData *)JS_ArenaGrow(&gData->pool,
+ gData->backTrackStack,
+ gData->maxBackTrack,
+ gData->maxBackTrack);
+ gData->maxBackTrack <<= 1;
+ if (!gData->backTrackStack)
+ return NULL;
+ result = (REBackTrackData *)((char *)gData->backTrackStack + offset);
+ }
+ gData->backTrackSP = result;
+ result->sz = gData->cursz;
+ gData->cursz = sz;
+
+ result->backtrack_op = op;
+ result->backtrack_pc = target;
+ result->cp = cp;
+ result->parenCount = parenCount;
+
+ result->precedingStateTop = gData->stateStackTop;
+ JS_ASSERT(gData->stateStackTop);
+ memcpy(result + 1, gData->stateStack,
+ sizeof(REProgState) * result->precedingStateTop);
+
+ if (parenCount != -1) {
+ result->parenIndex = parenIndex;
+ memcpy((char *)(result + 1)
+ + sizeof(REProgState) * result->precedingStateTop,
+ &x->parens[parenIndex],
+ sizeof(RECapture) * parenCount);
+ for (i = 0; i < parenCount; i++)
+ x->parens[parenIndex + i].index = -1;
+ }
+
+ return result;
+}
+
+
+/*
+ * Consecutive literal characters.
+ */
+#if 0
+static REMatchState *
+flatNMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
+ intN length)
+{
+ intN i;
+ if ((x->cp + length) > gData->cpend)
+ return NULL;
+ for (i = 0; i < length; i++) {
+ if (matchChars[i] != x->cp[i])
+ return NULL;
+ }
+ x->cp += length;
+ return x;
+}
+#endif
+
+static REMatchState *
+flatNIMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
+ intN length)
+{
+ intN i;
+ if ((x->cp + length) > gData->cpend)
+ return NULL;
+ for (i = 0; i < length; i++) {
+ if (upcase(matchChars[i]) != upcase(x->cp[i]))
+ return NULL;
+ }
+ x->cp += length;
+ return x;
+}
+
+/*
+ * 1. Evaluate DecimalEscape to obtain an EscapeValue E.
+ * 2. If E is not a character then go to step 6.
+ * 3. Let ch be E's character.
+ * 4. Let A be a one-element RECharSet containing the character ch.
+ * 5. Call CharacterSetMatcher(A, false) and return its Matcher result.
+ * 6. E must be an integer. Let n be that integer.
+ * 7. If n=0 or n>NCapturingParens then throw a SyntaxError exception.
+ * 8. Return an internal Matcher closure that takes two arguments, a State x
+ * and a Continuation c, and performs the following:
+ * 1. Let cap be x's captures internal array.
+ * 2. Let s be cap[n].
+ * 3. If s is undefined, then call c(x) and return its result.
+ * 4. Let e be x's endIndex.
+ * 5. Let len be s's length.
+ * 6. Let f be e+len.
+ * 7. If f>InputLength, return failure.
+ * 8. If there exists an integer i between 0 (inclusive) and len (exclusive)
+ * such that Canonicalize(s[i]) is not the same character as
+ * Canonicalize(Input [e+i]), then return failure.
+ * 9. Let y be the State (f, cap).
+ * 10. Call c(y) and return its result.
+ */
+static REMatchState *
+backrefMatcher(REGlobalData *gData, REMatchState *x, uintN parenIndex)
+{
+ uintN len;
+ uintN i;
+ const jschar *parenContent;
+ RECapture *s = &x->parens[parenIndex];
+ if (s->index == -1)
+ return x;
+
+ len = s->length;
+ if ((x->cp + len) > gData->cpend)
+ return NULL;
+
+ parenContent = &gData->cpbegin[s->index];
+ if (gData->regexp->flags & JSREG_FOLD) {
+ for (i = 0; i < len; i++) {
+ if (upcase(parenContent[i]) != upcase(x->cp[i]))
+ return NULL;
+ }
+ }
+ else {
+ for (i = 0; i < len; i++) {
+ if (parenContent[i] != x->cp[i])
+ return NULL;
+ }
+ }
+ x->cp += len;
+ return x;
+}
+
+
+/* Add a single character to the RECharSet */
+static void
+addCharacterToCharSet(RECharSet *cs, jschar c)
+{
+ uintN byteIndex = (uintN)(c / 8);
+ JS_ASSERT(c <= cs->length);
+ cs->u.bits[byteIndex] |= 1 << (c & 0x7);
+}
+
+
+/* Add a character range, c1 to c2 (inclusive) to the RECharSet */
+static void
+addCharacterRangeToCharSet(RECharSet *cs, jschar c1, jschar c2)
+{
+ uintN i;
+
+ uintN byteIndex1 = (uintN)(c1 / 8);
+ uintN byteIndex2 = (uintN)(c2 / 8);
+
+ JS_ASSERT((c2 <= cs->length) && (c1 <= c2));
+
+ c1 &= 0x7;
+ c2 &= 0x7;
+
+ if (byteIndex1 == byteIndex2)
+ cs->u.bits[byteIndex1] |= ((uint8)(0xFF) >> (7 - (c2 - c1))) << c1;
+ else {
+ cs->u.bits[byteIndex1] |= 0xFF << c1;
+ for (i = byteIndex1 + 1; i < byteIndex2; i++)
+ cs->u.bits[i] = 0xFF;
+ cs->u.bits[byteIndex2] |= (uint8)(0xFF) >> (7 - c2);
+ }
+}
+
+/* Compile the source of the class into a RECharSet */
+static JSBool
+processCharSet(REGlobalData *gData, RECharSet *charSet)
+{
+ const jschar *src = JSSTRING_CHARS(gData->regexp->source)
+ + charSet->u.src.startIndex;
+ const jschar *end = src + charSet->u.src.length;
+
+ jschar rangeStart, thisCh;
+ uintN byteLength;
+ jschar c;
+ uintN n;
+ intN nDigits;
+ intN i;
+ JSBool inRange = JS_FALSE;
+
+ JS_ASSERT(!charSet->converted);
+ charSet->converted = JS_TRUE;
+
+ byteLength = (charSet->length / 8) + 1;
+ charSet->u.bits = (uint8 *)JS_malloc(gData->cx, byteLength);
+ if (!charSet->u.bits)
+ return JS_FALSE;
+ memset(charSet->u.bits, 0, byteLength);
+
+ if (src == end)
+ return JS_TRUE;
+
+ if (*src == '^') {
+ JS_ASSERT(charSet->sense == JS_FALSE);
+ ++src;
+ }
+ else
+ JS_ASSERT(charSet->sense == JS_TRUE);
+
+
+ while (src != end) {
+ switch (*src) {
+ case '\\':
+ ++src;
+ c = *src++;
+ switch (c) {
+ case 'b':
+ thisCh = 0x8;
+ break;
+ case 'f':
+ thisCh = 0xC;
+ break;
+ case 'n':
+ thisCh = 0xA;
+ break;
+ case 'r':
+ thisCh = 0xD;
+ break;
+ case 't':
+ thisCh = 0x9;
+ break;
+ case 'v':
+ thisCh = 0xB;
+ break;
+ case 'c':
+ if (((src + 1) < end) && JS_ISWORD(src[1]))
+ thisCh = (jschar)(*src++ & 0x1F);
+ else {
+ --src;
+ thisCh = '\\';
+ }
+ break;
+ case 'x':
+ nDigits = 2;
+ goto lexHex;
+ case 'u':
+ nDigits = 4;
+lexHex:
+ n = 0;
+ for (i = 0; (i < nDigits) && (src < end); i++) {
+ uintN digit;
+ c = *src++;
+ if (!isASCIIHexDigit(c, &digit)) {
+ /*
+ * Back off to accepting the original '\'
+ * as a literal
+ */
+ src -= (i + 1);
+ n = '\\';
+ break;
+ }
+ n = (n << 4) | digit;
+ }
+ thisCh = (jschar)(n);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ /*
+ * This is a non-ECMA extension - decimal escapes (in this
+ * case, octal!) are supposed to be an error inside class
+ * ranges, but supported here for backwards compatibility.
+ *
+ */
+ n = JS7_UNDEC(c);
+ c = *src;
+ if ('0' <= c && c <= '7') {
+ src++;
+ n = 8 * n + JS7_UNDEC(c);
+ c = *src;
+ if ('0' <= c && c <= '7') {
+ src++;
+ i = 8 * n + JS7_UNDEC(c);
+ if (i <= 0377)
+ n = i;
+ else
+ src--;
+ }
+ }
+ thisCh = (jschar)(n);
+ break;
+
+ case 'd':
+ addCharacterRangeToCharSet(charSet, '0', '9');
+ continue; /* don't need range processing */
+ case 'D':
+ addCharacterRangeToCharSet(charSet, 0, '0' - 1);
+ addCharacterRangeToCharSet(charSet, (jschar)('9' + 1),
+ (jschar)(charSet->length));
+ continue;
+ case 's':
+ for (i = (intN)(charSet->length); i >= 0; i--)
+ if (JS_ISSPACE(i))
+ addCharacterToCharSet(charSet, (jschar)(i));
+ continue;
+ case 'S':
+ for (i = (intN)(charSet->length); i >= 0; i--)
+ if (!JS_ISSPACE(i))
+ addCharacterToCharSet(charSet, (jschar)(i));
+ continue;
+ case 'w':
+ for (i = (intN)(charSet->length); i >= 0; i--)
+ if (JS_ISWORD(i))
+ addCharacterToCharSet(charSet, (jschar)(i));
+ continue;
+ case 'W':
+ for (i = (intN)(charSet->length); i >= 0; i--)
+ if (!JS_ISWORD(i))
+ addCharacterToCharSet(charSet, (jschar)(i));
+ continue;
+ default:
+ thisCh = c;
+ break;
+
+ }
+ break;
+
+ default:
+ thisCh = *src++;
+ break;
+
+ }
+ if (inRange) {
+ if (gData->regexp->flags & JSREG_FOLD) {
+ addCharacterRangeToCharSet(charSet, upcase(rangeStart),
+ upcase(thisCh));
+ addCharacterRangeToCharSet(charSet, downcase(rangeStart),
+ downcase(thisCh));
+ } else {
+ addCharacterRangeToCharSet(charSet, rangeStart, thisCh);
+ }
+ inRange = JS_FALSE;
+ }
+ else {
+ if (gData->regexp->flags & JSREG_FOLD) {
+ addCharacterToCharSet(charSet, upcase(thisCh));
+ addCharacterToCharSet(charSet, downcase(thisCh));
+ } else {
+ addCharacterToCharSet(charSet, thisCh);
+ }
+ if (src < (end - 1)) {
+ if (*src == '-') {
+ ++src;
+ inRange = JS_TRUE;
+ rangeStart = thisCh;
+ }
+ }
+ }
+ }
+ return JS_TRUE;
+}
+
+void
+js_DestroyRegExp(JSContext *cx, JSRegExp *re)
+{
+ uintN i;
+ if (JS_ATOMIC_DECREMENT(&re->nrefs) == 0) {
+ if (re->classList) {
+ for (i = 0; i < re->classCount; i++) {
+ if (re->classList[i].converted)
+ JS_free(cx, re->classList[i].u.bits);
+ re->classList[i].u.bits = NULL;
+ }
+ JS_free(cx, re->classList);
+ }
+ JS_free(cx, re);
+ }
+}
+
+static JSBool
+reallocStateStack(REGlobalData *gData)
+{
+ size_t sz = sizeof(REProgState) * gData->maxStateStack;
+ gData->maxStateStack <<= 1;
+ gData->stateStack
+ = (REProgState *)JS_ArenaGrow(&gData->pool, gData->stateStack, sz, sz);
+ if (!gData->stateStack) {
+ gData->ok = JS_FALSE;
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+/*
+* Apply the current op against the given input to see if
+* it's going to match or fail. Return false if we don't
+* get a match, true if we do and update the state of the
+* input and pc if the update flag is true.
+*/
+static REMatchState *simpleMatch(REGlobalData *gData, REMatchState *x,
+ REOp op, jsbytecode **startpc, JSBool update)
+{
+ REMatchState *result = NULL;
+ jschar matchCh;
+ intN parenIndex;
+ intN offset, length, index;
+ jsbytecode *pc = *startpc; /* pc has already been incremented past op */
+ jschar *source;
+ const jschar *startcp = x->cp;
+ jschar ch;
+ RECharSet *charSet;
+
+
+ switch (op) {
+ default:
+ JS_ASSERT(JS_FALSE);
+ case REOP_BOL:
+ if (x->cp != gData->cpbegin) {
+ if (gData->cx->regExpStatics.multiline ||
+ (gData->regexp->flags & JSREG_MULTILINE)) {
+ if (!RE_IS_LINE_TERM(x->cp[-1]))
+ break;
+ }
+ else
+ break;
+ }
+ result = x;
+ break;
+ case REOP_EOL:
+ if (x->cp != gData->cpend) {
+ if (gData->cx->regExpStatics.multiline ||
+ (gData->regexp->flags & JSREG_MULTILINE)) {
+ if (!RE_IS_LINE_TERM(*x->cp))
+ break;
+ }
+ else
+ break;
+ }
+ result = x;
+ break;
+ case REOP_WBDRY:
+ if ((x->cp == gData->cpbegin || !JS_ISWORD(x->cp[-1]))
+ ^ !((x->cp != gData->cpend) && JS_ISWORD(*x->cp)))
+ result = x;
+ break;
+ case REOP_WNONBDRY:
+ if ((x->cp == gData->cpbegin || !JS_ISWORD(x->cp[-1]))
+ ^ ((x->cp != gData->cpend) && JS_ISWORD(*x->cp)))
+ result = x;
+ break;
+ case REOP_DOT:
+ if (x->cp != gData->cpend && !RE_IS_LINE_TERM(*x->cp)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_DIGIT:
+ if (x->cp != gData->cpend && JS_ISDIGIT(*x->cp)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_NONDIGIT:
+ if (x->cp != gData->cpend && !JS_ISDIGIT(*x->cp)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_ALNUM:
+ if (x->cp != gData->cpend && JS_ISWORD(*x->cp)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_NONALNUM:
+ if (x->cp != gData->cpend && !JS_ISWORD(*x->cp)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_SPACE:
+ if (x->cp != gData->cpend && JS_ISSPACE(*x->cp)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_NONSPACE:
+ if (x->cp != gData->cpend && !JS_ISSPACE(*x->cp)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_BACKREF:
+ parenIndex = GET_ARG(pc);
+ pc += ARG_LEN;
+ result = backrefMatcher(gData, x, parenIndex);
+ break;
+ case REOP_FLAT:
+ offset = GET_ARG(pc);
+ pc += ARG_LEN;
+ length = GET_ARG(pc);
+ pc += ARG_LEN;
+ source = JSSTRING_CHARS(gData->regexp->source) + offset;
+ if ((x->cp + length) <= gData->cpend) {
+ for (index = 0; index < length; index++) {
+ if (source[index] != x->cp[index])
+ return NULL;
+ }
+ x->cp += length;
+ result = x;
+ }
+ break;
+ case REOP_FLAT1:
+ matchCh = *pc++;
+ if ((x->cp != gData->cpend) && (*x->cp == matchCh)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_FLATi:
+ offset = GET_ARG(pc);
+ pc += ARG_LEN;
+ length = GET_ARG(pc);
+ pc += ARG_LEN;
+ source = JSSTRING_CHARS(gData->regexp->source);
+ result = flatNIMatcher(gData, x, source + offset, length);
+ break;
+ case REOP_FLAT1i:
+ matchCh = *pc++;
+ if ((x->cp != gData->cpend) && (upcase(*x->cp) == upcase(matchCh))) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_UCFLAT1:
+ matchCh = GET_ARG(pc);
+ pc += ARG_LEN;
+ if ((x->cp != gData->cpend) && (*x->cp == matchCh)) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_UCFLAT1i:
+ matchCh = GET_ARG(pc);
+ pc += ARG_LEN;
+ if ((x->cp != gData->cpend) && (upcase(*x->cp) == upcase(matchCh))) {
+ result = x;
+ result->cp++;
+ }
+ break;
+ case REOP_CLASS:
+ index = GET_ARG(pc);
+ pc += ARG_LEN;
+ if (x->cp != gData->cpend) {
+ charSet = &gData->regexp->classList[index];
+ JS_ASSERT(charSet->converted);
+ ch = *x->cp;
+ index = ch / 8;
+ if ((charSet->length != 0) &&
+ ( (ch <= charSet->length)
+ && ((charSet->u.bits[index] & (1 << (ch & 0x7))) != 0) )) {
+ result = x;
+ result->cp++;
+ }
+ }
+ break;
+ case REOP_NCLASS:
+ index = GET_ARG(pc);
+ pc += ARG_LEN;
+ if (x->cp != gData->cpend) {
+ charSet = &gData->regexp->classList[index];
+ JS_ASSERT(charSet->converted);
+ ch = *x->cp;
+ index = ch / 8;
+ if ((charSet->length == 0) ||
+ ( (ch > charSet->length)
+ || ((charSet->u.bits[index] & (1 << (ch & 0x7))) == 0) )) {
+ result = x;
+ result->cp++;
+ }
+ }
+ break;
+ }
+ if (result != NULL) {
+ if (update)
+ *startpc = pc;
+ else
+ x->cp = startcp;
+ return result;
+ }
+ x->cp = startcp;
+ return NULL;
+}
+
+static REMatchState *
+executeREBytecode(REGlobalData *gData, REMatchState *x)
+{
+ REMatchState *result;
+ REBackTrackData *backTrackData;
+ intN offset;
+ jsbytecode *nextpc;
+ REOp nextop;
+ RECapture *cap;
+ REProgState *curState;
+ const jschar *startcp;
+ uintN parenIndex, k;
+ uintN parenSoFar = 0;
+
+ jschar matchCh1, matchCh2;
+ RECharSet *charSet;
+
+ JSBool anchor;
+ jsbytecode *pc = gData->regexp->program;
+ REOp op = (REOp)(*pc++);
+
+ /*
+ * If the first node is a simple match, step the index into
+ * the string until that match is made, or fail if it can't be
+ * found at all.
+ */
+ if (REOP_IS_SIMPLE(op)) {
+ anchor = JS_FALSE;
+ while (x->cp <= gData->cpend) {
+ nextpc = pc; /* reset back to start each time */
+ result = simpleMatch(gData, x, op, &nextpc, JS_TRUE);
+ if (result) {
+ anchor = JS_TRUE;
+ x = result;
+ pc = nextpc; /* accept skip to next opcode */
+ op = (REOp)(*pc++);
+ break;
+ }
+ else {
+ gData->skipped++;
+ x->cp++;
+ }
+ }
+ if (!anchor)
+ return NULL;
+ }
+
+ while (JS_TRUE) {
+ if (REOP_IS_SIMPLE(op))
+ result = simpleMatch(gData, x, op, &pc, JS_TRUE);
+ else {
+ curState = &gData->stateStack[gData->stateStackTop];
+ switch (op) {
+ case REOP_EMPTY:
+ result = x;
+ break;
+
+ case REOP_ALTPREREQ2:
+ nextpc = pc + GET_OFFSET(pc); /* start of next op */
+ pc += ARG_LEN;
+ matchCh2 = GET_ARG(pc);
+ pc += ARG_LEN;
+ k = GET_ARG(pc);
+ pc += ARG_LEN;
+
+ if (x->cp != gData->cpend) {
+ if (*x->cp == matchCh2)
+ goto doAlt;
+
+ charSet = &gData->regexp->classList[k];
+ if (!charSet->converted)
+ if (!processCharSet(gData, charSet))
+ return NULL;
+ matchCh1 = *x->cp;
+ k = matchCh1 / 8;
+ if ((charSet->length == 0 ||
+ matchCh1 > charSet->length ||
+ (charSet->u.bits[k] & (1 << (matchCh1 & 0x7))) == 0)
+ ^ charSet->sense) {
+ goto doAlt;
+ }
+ }
+ result = NULL;
+ break;
+
+ case REOP_ALTPREREQ:
+ nextpc = pc + GET_OFFSET(pc); /* start of next op */
+ pc += ARG_LEN;
+ matchCh1 = GET_ARG(pc);
+ pc += ARG_LEN;
+ matchCh2 = GET_ARG(pc);
+ pc += ARG_LEN;
+ if ((x->cp == gData->cpend)
+ || ((*x->cp != matchCh1) && (*x->cp != matchCh2))) {
+ result = NULL;
+ break;
+ }
+ /* else false thru... */
+
+ case REOP_ALT:
+doAlt:
+ nextpc = pc + GET_OFFSET(pc); /* start of next alternate */
+ pc += ARG_LEN; /* start of this alternate */
+ curState->parenSoFar = parenSoFar;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ op = (REOp)(*pc++);
+ startcp = x->cp;
+ if (REOP_IS_SIMPLE(op)) {
+ if (!simpleMatch(gData, x, op, &pc, JS_TRUE)) {
+ op = (REOp)(*nextpc++);
+ pc = nextpc;
+ continue;
+ }
+ else { /* accept the match and move on */
+ result = x;
+ op = (REOp)(*pc++);
+ }
+ }
+ nextop = (REOp)(*nextpc++);
+ if (!pushBackTrackState(gData, nextop, nextpc, x, startcp, 0, 0))
+ return NULL;
+ continue;
+
+ /*
+ * Occurs at (succesful) end of REOP_ALT,
+ */
+ case REOP_JUMP:
+ --gData->stateStackTop;
+ offset = GET_OFFSET(pc);
+ pc += offset;
+ op = (REOp)(*pc++);
+ continue;
+
+ /*
+ * Occurs at last (succesful) end of REOP_ALT,
+ */
+ case REOP_ENDALT:
+ --gData->stateStackTop;
+ op = (REOp)(*pc++);
+ continue;
+
+ case REOP_LPAREN:
+ parenIndex = GET_ARG(pc);
+ if ((parenIndex + 1) > parenSoFar)
+ parenSoFar = parenIndex + 1;
+ pc += ARG_LEN;
+ x->parens[parenIndex].index = x->cp - gData->cpbegin;
+ x->parens[parenIndex].length = 0;
+ op = (REOp)(*pc++);
+ continue;
+ case REOP_RPAREN:
+ parenIndex = GET_ARG(pc);
+ pc += ARG_LEN;
+ cap = &x->parens[parenIndex];
+ cap->length = x->cp - (gData->cpbegin + cap->index);
+ op = (REOp)(*pc++);
+ continue;
+
+ case REOP_ASSERT:
+ nextpc = pc + GET_OFFSET(pc); /* start of term after ASSERT */
+ pc += ARG_LEN; /* start of ASSERT child */
+ op = (REOp)(*pc++);
+ if (REOP_IS_SIMPLE(op)
+ && !simpleMatch(gData, x, op, &pc, JS_FALSE)) {
+ result = NULL;
+ break;
+ }
+ else {
+ curState->u.assertion.top
+ = (char *)gData->backTrackSP
+ - (char *)gData->backTrackStack;
+ curState->u.assertion.sz = gData->cursz;
+ curState->index = x->cp - gData->cpbegin;
+ curState->parenSoFar = parenSoFar;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ if (!pushBackTrackState(gData, REOP_ASSERTTEST,
+ nextpc, x, x->cp, 0, 0))
+ return NULL;
+ }
+ continue;
+ case REOP_ASSERT_NOT:
+ nextpc = pc + GET_OFFSET(pc);
+ pc += ARG_LEN;
+ op = (REOp)(*pc++);
+ if (REOP_IS_SIMPLE(op)
+ /* Note - fail to fail! */
+ && simpleMatch(gData, x, op, &pc, JS_FALSE)) {
+ result = NULL;
+ break;
+ }
+ else {
+ curState->u.assertion.top
+ = (char *)gData->backTrackSP
+ - (char *)gData->backTrackStack;
+ curState->u.assertion.sz = gData->cursz;
+ curState->index = x->cp - gData->cpbegin;
+ curState->parenSoFar = parenSoFar;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ if (!pushBackTrackState(gData, REOP_ASSERTNOTTEST,
+ nextpc, x, x->cp, 0, 0))
+ return NULL;
+ }
+ continue;
+ case REOP_ASSERTTEST:
+ --gData->stateStackTop;
+ --curState;
+ x->cp = gData->cpbegin + curState->index;
+ gData->backTrackSP
+ = (REBackTrackData *)((char *)gData->backTrackStack
+ + curState->u.assertion.top);
+ gData->cursz = curState->u.assertion.sz;
+ if (result != NULL)
+ result = x;
+ break;
+ case REOP_ASSERTNOTTEST:
+ --gData->stateStackTop;
+ --curState;
+ x->cp = gData->cpbegin + curState->index;
+ gData->backTrackSP
+ = (REBackTrackData *)((char *)gData->backTrackStack
+ + curState->u.assertion.top);
+ gData->cursz = curState->u.assertion.sz;
+ if (result == NULL)
+ result = x;
+ else
+ result = NULL;
+ break;
+
+ case REOP_END:
+ if (x != NULL)
+ return x;
+ break;
+
+ case REOP_STAR:
+ curState->u.quantifier.min = 0;
+ curState->u.quantifier.max = -1;
+ goto quantcommon;
+ case REOP_PLUS:
+ curState->u.quantifier.min = 1;
+ curState->u.quantifier.max = -1;
+ goto quantcommon;
+ case REOP_OPT:
+ curState->u.quantifier.min = 0;
+ curState->u.quantifier.max = 1;
+ goto quantcommon;
+ case REOP_QUANT:
+ curState->u.quantifier.min = GET_ARG(pc);
+ pc += ARG_LEN;
+ curState->u.quantifier.max = GET_ARG(pc);
+ pc += ARG_LEN;
+quantcommon:
+ if (curState->u.quantifier.max == 0) {
+ pc = pc + GET_OFFSET(pc);
+ op = (REOp)(*pc++);
+ result = x;
+ continue;
+ }
+ /* Step over <next> */
+ nextpc = pc + ARG_LEN;
+ op = (REOp)(*nextpc++);
+ startcp = x->cp;
+ if (REOP_IS_SIMPLE(op)) {
+ if (!simpleMatch(gData, x, op, &nextpc, JS_TRUE)) {
+ if (curState->u.quantifier.min == 0)
+ result = x;
+ else
+ result = NULL;
+ pc = pc + GET_OFFSET(pc);
+ break;
+ }
+ else {
+ op = (REOp)(*nextpc++);
+ result = x;
+ }
+ }
+ curState->index = startcp - gData->cpbegin;
+ curState->continue_op = REOP_REPEAT;
+ curState->continue_pc = pc;
+ curState->parenSoFar = parenSoFar;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ if (curState->u.quantifier.min == 0)
+ if (!pushBackTrackState(gData, REOP_REPEAT,
+ pc, x, startcp, 0, 0))
+ return NULL;
+ pc = nextpc;
+ continue;
+
+ case REOP_ENDCHILD: /* marks the end of a quantifier child */
+ pc = curState[-1].continue_pc;
+ op = curState[-1].continue_op;
+ continue;
+
+ case REOP_REPEAT:
+ --curState;
+repeatAgain:
+ --gData->stateStackTop;
+ if (result == NULL) {
+ /*
+ * There's been a failure, see if we have enough children.
+ */
+ if (curState->u.quantifier.min == 0) {
+ result = x;
+ goto repeatDone;
+ }
+ break;
+ }
+ else {
+ if ((curState->u.quantifier.min == 0)
+ && (x->cp == gData->cpbegin + curState->index)) {
+ /* matched an empty string, that'll get us nowhere */
+ result = NULL;
+ break;
+ }
+ if (curState->u.quantifier.min != 0)
+ curState->u.quantifier.min--;
+ if (curState->u.quantifier.max != (uint16)(-1))
+ curState->u.quantifier.max--;
+ if (curState->u.quantifier.max == 0) {
+ result = x;
+ goto repeatDone;
+ }
+ nextpc = pc + ARG_LEN;
+ nextop = (REOp)(*nextpc);
+ startcp = x->cp;
+ if (REOP_IS_SIMPLE(nextop)) {
+ nextpc++;
+ if (!simpleMatch(gData, x, nextop, &nextpc, JS_TRUE)) {
+ if (curState->u.quantifier.min == 0) {
+ result = x;
+ goto repeatDone;
+ }
+ else
+ result = NULL;
+ break;
+ }
+ result = x;
+ }
+ curState->index = startcp - gData->cpbegin;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ if (curState->u.quantifier.min == 0)
+ if (!pushBackTrackState(gData, REOP_REPEAT,
+ pc, x, startcp,
+ curState->parenSoFar,
+ parenSoFar
+ - curState->parenSoFar))
+ return NULL;
+ if (*nextpc == REOP_ENDCHILD)
+ goto repeatAgain;
+ pc = nextpc;
+ op = (REOp)(*pc++);
+ parenSoFar = curState->parenSoFar;
+ }
+ continue;
+repeatDone:
+ pc = pc + GET_OFFSET(pc);
+ break;
+
+
+ case REOP_MINIMALSTAR:
+ curState->u.quantifier.min = 0;
+ curState->u.quantifier.max = -1;
+ goto minimalquantcommon;
+ case REOP_MINIMALPLUS:
+ curState->u.quantifier.min = 1;
+ curState->u.quantifier.max = -1;
+ goto minimalquantcommon;
+ case REOP_MINIMALOPT:
+ curState->u.quantifier.min = 0;
+ curState->u.quantifier.max = 1;
+ goto minimalquantcommon;
+ case REOP_MINIMALQUANT:
+ curState->u.quantifier.min = GET_ARG(pc);
+ pc += ARG_LEN;
+ curState->u.quantifier.max = GET_ARG(pc);
+ pc += ARG_LEN;
+minimalquantcommon:
+ curState->index = x->cp - gData->cpbegin;
+ curState->parenSoFar = parenSoFar;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ if (curState->u.quantifier.min != 0) {
+ curState->continue_op = REOP_MINIMALREPEAT;
+ curState->continue_pc = pc;
+ /* step over <next> */
+ pc += ARG_LEN;
+ op = (REOp)(*pc++);
+ }
+ else {
+ if (!pushBackTrackState(gData, REOP_MINIMALREPEAT,
+ pc, x, x->cp, 0, 0))
+ return NULL;
+ --gData->stateStackTop;
+ pc = pc + GET_OFFSET(pc);
+ op = (REOp)(*pc++);
+ }
+ continue;
+
+ case REOP_MINIMALREPEAT:
+ --gData->stateStackTop;
+ --curState;
+
+ if (result == NULL) {
+ /*
+ * Non-greedy failure - try to consume another child.
+ */
+ if ((curState->u.quantifier.max == (uint16)(-1))
+ || (curState->u.quantifier.max > 0)) {
+ curState->index = x->cp - gData->cpbegin;
+ curState->continue_op = REOP_MINIMALREPEAT;
+ curState->continue_pc = pc;
+ pc += ARG_LEN;
+ for (k = curState->parenSoFar; k < parenSoFar; k++)
+ x->parens[k].index = -1;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ op = (REOp)(*pc++);
+ continue;
+ }
+ else {
+ /* Don't need to adjust pc since we're going to pop. */
+ break;
+ }
+ }
+ else {
+ if ((curState->u.quantifier.min == 0)
+ && (x->cp == gData->cpbegin + curState->index)) {
+ /* Matched an empty string, that'll get us nowhere. */
+ result = NULL;
+ break;
+ }
+ if (curState->u.quantifier.min != 0)
+ curState->u.quantifier.min--;
+ if (curState->u.quantifier.max != (uint16)(-1))
+ curState->u.quantifier.max--;
+ if (curState->u.quantifier.min != 0) {
+ curState->continue_op = REOP_MINIMALREPEAT;
+ curState->continue_pc = pc;
+ pc += ARG_LEN;
+ for (k = curState->parenSoFar; k < parenSoFar; k++)
+ x->parens[k].index = -1;
+ curState->index = x->cp - gData->cpbegin;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ op = (REOp)(*pc++);
+ continue;
+ }
+ else {
+ curState->index = x->cp - gData->cpbegin;
+ curState->parenSoFar = parenSoFar;
+ ++gData->stateStackTop;
+ if (gData->stateStackTop == gData->maxStateStack)
+ if (!reallocStateStack(gData))
+ return NULL;
+ if (!pushBackTrackState(gData, REOP_MINIMALREPEAT,
+ pc, x, x->cp,
+ curState->parenSoFar,
+ parenSoFar
+ - curState->parenSoFar))
+ return NULL;
+ --gData->stateStackTop;
+ pc = pc + GET_OFFSET(pc);
+ op = (REOp)(*pc++);
+ continue;
+ }
+ }
+
+ default:
+ JS_ASSERT(JS_FALSE);
+ result = NULL;
+ }
+ }
+ /*
+ * If the match failed and there's a backtrack option, take it.
+ * Otherwise this is a complete and utter failure.
+ */
+ if (result == NULL) {
+ if (gData->cursz > 0) {
+ backTrackData = gData->backTrackSP;
+ gData->cursz = backTrackData->sz;
+ gData->backTrackSP
+ = (REBackTrackData *)((char *)backTrackData
+ - backTrackData->sz);
+ x->cp = backTrackData->cp;
+ pc = backTrackData->backtrack_pc;
+ op = backTrackData->backtrack_op;
+ gData->stateStackTop = backTrackData->precedingStateTop;
+ JS_ASSERT(gData->stateStackTop);
+
+ memcpy(gData->stateStack, backTrackData + 1,
+ sizeof(REProgState) * backTrackData->precedingStateTop);
+ curState = &gData->stateStack[gData->stateStackTop - 1];
+
+ if (backTrackData->parenCount) {
+ memcpy(&x->parens[backTrackData->parenIndex],
+ (char *)(backTrackData + 1) + sizeof(REProgState) * backTrackData->precedingStateTop,
+ sizeof(RECapture) * backTrackData->parenCount);
+ parenSoFar = backTrackData->parenIndex + backTrackData->parenCount;
+ }
+ else {
+ for (k = curState->parenSoFar; k < parenSoFar; k++)
+ x->parens[k].index = -1;
+ parenSoFar = curState->parenSoFar;
+ }
+ continue;
+ }
+ else
+ return NULL;
+ }
+ else
+ x = result;
+
+ /*
+ * Continue with the expression.
+ */
+ op = (REOp)*pc++;
+ }
+ return NULL;
+}
+
+static REMatchState *
+MatchRegExp(REGlobalData *gData, REMatchState *x)
+{
+ REMatchState *result;
+ const jschar *cp = x->cp;
+ const jschar *cp2;
+ uintN j;
+
+ /*
+ * Have to include the position beyond the last character
+ * in order to detect end-of-input/line condition.
+ */
+ for (cp2 = cp; cp2 <= gData->cpend; cp2++) {
+ gData->skipped = cp2 - cp;
+ x->cp = cp2;
+ for (j = 0; j < gData->regexp->parenCount; j++)
+ x->parens[j].index = -1;
+ result = executeREBytecode(gData, x);
+ if (!gData->ok || result)
+ return result;
+ gData->backTrackSP = gData->backTrackStack;
+ gData->cursz = 0;
+ gData->stateStackTop = 0;
+ cp2 = cp + gData->skipped;
+ }
+ return NULL;
+}
+
+
+static REMatchState *
+initMatch(JSContext *cx, REGlobalData *gData, JSRegExp *re)
+{
+ REMatchState *result;
+ uintN i;
+
+ gData->maxBackTrack = INITIAL_BACKTRACK;
+ JS_ARENA_ALLOCATE_CAST(gData->backTrackStack, REBackTrackData *,
+ &gData->pool,
+ INITIAL_BACKTRACK);
+ if (!gData->backTrackStack)
+ return NULL;
+ gData->backTrackSP = gData->backTrackStack;
+ gData->cursz = 0;
+
+
+ gData->maxStateStack = INITIAL_STATESTACK;
+ JS_ARENA_ALLOCATE_CAST(gData->stateStack, REProgState *,
+ &gData->pool,
+ sizeof(REProgState) * INITIAL_STATESTACK);
+ if (!gData->stateStack)
+ return NULL;
+ gData->stateStackTop = 0;
+
+ gData->cx = cx;
+ gData->regexp = re;
+ gData->ok = JS_TRUE;
+
+ JS_ARENA_ALLOCATE_CAST(result, REMatchState *,
+ &gData->pool,
+ sizeof(REMatchState)
+ + (re->parenCount - 1) * sizeof(RECapture));
+ if (!result)
+ return NULL;
+
+ for (i = 0; i < re->classCount; i++)
+ if (!re->classList[i].converted)
+ if (!processCharSet(gData, &re->classList[i]))
+ return NULL;
+
+ return result;
+}
+
+JSBool
+js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
+ JSBool test, jsval *rval)
+{
+ REGlobalData gData;
+ REMatchState *x, *result;
+
+ const jschar *cp, *ep;
+ size_t i, length, start;
+ JSSubString *morepar;
+ JSBool ok;
+ JSRegExpStatics *res;
+ ptrdiff_t matchlen;
+ uintN num, morenum;
+ JSString *parstr, *matchstr;
+ JSObject *obj;
+
+ RECapture *parsub;
+
+ /*
+ * It's safe to load from cp because JSStrings have a zero at the end,
+ * and we never let cp get beyond cpend.
+ */
+ start = *indexp;
+ length = JSSTRING_LENGTH(str);
+ if (start > length)
+ start = length;
+ cp = JSSTRING_CHARS(str);
+ gData.cpbegin = cp;
+ gData.cpend = cp + length;
+ cp += start;
+ gData.start = start;
+ gData.skipped = 0;
+
+ JS_InitArenaPool(&gData.pool, "RegExpPool", 8096, 4);
+ x = initMatch(cx, &gData, re);
+ if (!x)
+ return JS_FALSE;
+ x->cp = cp;
+
+ /*
+ * Call the recursive matcher to do the real work. Return null on mismatch
+ * whether testing or not. On match, return an extended Array object.
+ */
+ result = MatchRegExp(&gData, x);
+ if (!(ok = gData.ok)) goto out;
+ if (!result) {
+ *rval = JSVAL_NULL;
+ goto out;
+ }
+ cp = result->cp;
+ i = PTRDIFF(cp, gData.cpbegin, jschar);
+ *indexp = i;
+ matchlen = i - (start + gData.skipped);
+ ep = cp;
+ cp -= matchlen;
+
+ if (test) {
+ /*
+ * Testing for a match and updating cx->regExpStatics: don't allocate
+ * an array object, do return true.
+ */
+ *rval = JSVAL_TRUE;
+
+ /* Avoid warning. (gcc doesn't detect that obj is needed iff !test); */
+ obj = NULL;
+ } else {
+ /*
+ * The array returned on match has element 0 bound to the matched
+ * string, elements 1 through state.parenCount bound to the paren
+ * matches, an index property telling the length of the left context,
+ * and an input property referring to the input string.
+ */
+ obj = js_NewArrayObject(cx, 0, NULL);
+ if (!obj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ *rval = OBJECT_TO_JSVAL(obj);
+
+#define DEFVAL(val, id) { \
+ ok = js_DefineProperty(cx, obj, id, val, \
+ JS_PropertyStub, JS_PropertyStub, \
+ JSPROP_ENUMERATE, NULL); \
+ if (!ok) { \
+ cx->newborn[GCX_OBJECT] = NULL; \
+ cx->newborn[GCX_STRING] = NULL; \
+ goto out; \
+ } \
+}
+
+ matchstr = js_NewStringCopyN(cx, cp, matchlen, 0);
+ if (!matchstr) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ ok = JS_FALSE;
+ goto out;
+ }
+ DEFVAL(STRING_TO_JSVAL(matchstr), INT_TO_JSVAL(0));
+ }
+
+ res = &cx->regExpStatics;
+ res->input = str;
+ res->parenCount = re->parenCount;
+ if (re->parenCount == 0)
+ res->lastParen = js_EmptySubString;
+ else {
+ for (num = 0; num < re->parenCount; num++) {
+ parsub = &result->parens[num];
+ if (num < 9) {
+ if (parsub->index == -1) {
+ res->parens[num].chars = NULL;
+ res->parens[num].length = 0;
+ }
+ else {
+ res->parens[num].chars = gData.cpbegin + parsub->index;
+ res->parens[num].length = parsub->length;
+ }
+ } else {
+ morenum = num - 9;
+ morepar = res->moreParens;
+ if (!morepar) {
+ res->moreLength = 10;
+ morepar = (JSSubString*) JS_malloc(cx,
+ 10 * sizeof(JSSubString));
+ } else if (morenum >= res->moreLength) {
+ res->moreLength += 10;
+ morepar = (JSSubString*) JS_realloc(cx, morepar,
+ res->moreLength * sizeof(JSSubString));
+ }
+ if (!morepar) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ cx->newborn[GCX_STRING] = NULL;
+ ok = JS_FALSE;
+ goto out;
+ }
+ res->moreParens = morepar;
+ if (parsub->index == -1) {
+ morepar[morenum].chars = NULL;
+ morepar[morenum].length = 0;
+ }
+ else {
+ morepar[morenum].chars = gData.cpbegin + parsub->index;
+ morepar[morenum].length = parsub->length;
+ }
+ }
+ if (test)
+ continue;
+ if (parsub->index == -1)
+ ok = js_DefineProperty(cx, obj, INT_TO_JSVAL(num + 1),
+ JSVAL_VOID, NULL, NULL,
+ JSPROP_ENUMERATE, NULL);
+ else {
+ parstr = js_NewStringCopyN(cx, gData.cpbegin + parsub->index,
+ parsub->length, 0);
+ if (!parstr) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ cx->newborn[GCX_STRING] = NULL;
+ ok = JS_FALSE;
+ goto out;
+ }
+ ok = js_DefineProperty(cx, obj, INT_TO_JSVAL(num + 1),
+ STRING_TO_JSVAL(parstr), NULL, NULL,
+ JSPROP_ENUMERATE, NULL);
+ }
+ if (!ok) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ cx->newborn[GCX_STRING] = NULL;
+ goto out;
+ }
+ }
+ if (parsub->index == -1) {
+ res->lastParen.chars = NULL;
+ res->lastParen.length = 0;
+ }
+ else {
+ res->lastParen.chars = gData.cpbegin + parsub->index;
+ res->lastParen.length = parsub->length;
+ }
+ }
+
+ if (!test) {
+ /*
+ * Define the index and input properties last for better for/in loop
+ * order (so they come after the elements).
+ */
+ DEFVAL(INT_TO_JSVAL(start + gData.skipped),
+ (jsid)cx->runtime->atomState.indexAtom);
+ DEFVAL(STRING_TO_JSVAL(str),
+ (jsid)cx->runtime->atomState.inputAtom);
+ }
+
+#undef DEFVAL
+
+ res->lastMatch.chars = cp;
+ res->lastMatch.length = matchlen;
+ if (cx->version == JSVERSION_1_2) {
+ /*
+ * JS1.2 emulated Perl4.0.1.8 (patch level 36) for global regexps used
+ * in scalar contexts, and unintentionally for the string.match "list"
+ * psuedo-context. On "hi there bye", the following would result:
+ *
+ * Language while(/ /g){print("$`");} s/ /$`/g
+ * perl4.036 "hi", "there" "hihitherehi therebye"
+ * perl5 "hi", "hi there" "hihitherehi therebye"
+ * js1.2 "hi", "there" "hihitheretherebye"
+ */
+ res->leftContext.chars = JSSTRING_CHARS(str) + start;
+ res->leftContext.length = gData.skipped;
+ } else {
+ /*
+ * For JS1.3 and ECMAv2, emulate Perl5 exactly:
+ *
+ * js1.3 "hi", "hi there" "hihitherehi therebye"
+ */
+ res->leftContext.chars = JSSTRING_CHARS(str);
+ res->leftContext.length = start + gData.skipped;
+ }
+ res->rightContext.chars = ep;
+ res->rightContext.length = gData.cpend - ep;
+
+out:
+ JS_FinishArenaPool(&gData.pool);
+ return ok;
+}
+
+/************************************************************************/
+
+enum regexp_tinyid {
+ REGEXP_SOURCE = -1,
+ REGEXP_GLOBAL = -2,
+ REGEXP_IGNORE_CASE = -3,
+ REGEXP_LAST_INDEX = -4,
+ REGEXP_MULTILINE = -5
+};
+
+#define REGEXP_PROP_ATTRS (JSPROP_PERMANENT|JSPROP_SHARED)
+
+static JSPropertySpec regexp_props[] = {
+ {"source", REGEXP_SOURCE, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
+ {"global", REGEXP_GLOBAL, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
+ {"ignoreCase", REGEXP_IGNORE_CASE, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
+ {"lastIndex", REGEXP_LAST_INDEX, REGEXP_PROP_ATTRS,0,0},
+ {"multiline", REGEXP_MULTILINE, REGEXP_PROP_ATTRS | JSPROP_READONLY,0,0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsint slot;
+ JSRegExp *re;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ slot = JSVAL_TO_INT(id);
+ if (slot == REGEXP_LAST_INDEX)
+ return JS_GetReservedSlot(cx, obj, 0, vp);
+
+ JS_LOCK_OBJ(cx, obj);
+ re = (JSRegExp *) JS_GetInstancePrivate(cx, obj, &js_RegExpClass, NULL);
+ if (re) {
+ switch (slot) {
+ case REGEXP_SOURCE:
+ *vp = STRING_TO_JSVAL(re->source);
+ break;
+ case REGEXP_GLOBAL:
+ *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_GLOB) != 0);
+ break;
+ case REGEXP_IGNORE_CASE:
+ *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_FOLD) != 0);
+ break;
+ case REGEXP_MULTILINE:
+ *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_MULTILINE) != 0);
+ break;
+ }
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+ return JS_TRUE;
+}
+
+static JSBool
+regexp_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSBool ok;
+ jsint slot;
+ jsdouble lastIndex;
+
+ ok = JS_TRUE;
+ if (!JSVAL_IS_INT(id))
+ return ok;
+ slot = JSVAL_TO_INT(id);
+ if (slot == REGEXP_LAST_INDEX) {
+ if (!js_ValueToNumber(cx, *vp, &lastIndex))
+ return JS_FALSE;
+ lastIndex = js_DoubleToInteger(lastIndex);
+ ok = js_NewNumberValue(cx, lastIndex, vp) &&
+ JS_SetReservedSlot(cx, obj, 0, *vp);
+ }
+ return ok;
+}
+
+/*
+ * RegExp class static properties and their Perl counterparts:
+ *
+ * RegExp.input $_
+ * RegExp.multiline $*
+ * RegExp.lastMatch $&
+ * RegExp.lastParen $+
+ * RegExp.leftContext $`
+ * RegExp.rightContext $'
+ */
+enum regexp_static_tinyid {
+ REGEXP_STATIC_INPUT = -1,
+ REGEXP_STATIC_MULTILINE = -2,
+ REGEXP_STATIC_LAST_MATCH = -3,
+ REGEXP_STATIC_LAST_PAREN = -4,
+ REGEXP_STATIC_LEFT_CONTEXT = -5,
+ REGEXP_STATIC_RIGHT_CONTEXT = -6
+};
+
+JSBool
+js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res)
+{
+ JS_ClearRegExpStatics(cx);
+ return js_AddRoot(cx, &res->input, "res->input");
+}
+
+void
+js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res)
+{
+ if (res->moreParens) {
+ JS_free(cx, res->moreParens);
+ res->moreParens = NULL;
+ }
+ js_RemoveRoot(cx->runtime, &res->input);
+}
+
+static JSBool
+regexp_static_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsint slot;
+ JSRegExpStatics *res;
+ JSString *str;
+ JSSubString *sub;
+
+ res = &cx->regExpStatics;
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ slot = JSVAL_TO_INT(id);
+ switch (slot) {
+ case REGEXP_STATIC_INPUT:
+ *vp = res->input ? STRING_TO_JSVAL(res->input)
+ : JS_GetEmptyStringValue(cx);
+ return JS_TRUE;
+ case REGEXP_STATIC_MULTILINE:
+ *vp = BOOLEAN_TO_JSVAL(res->multiline);
+ return JS_TRUE;
+ case REGEXP_STATIC_LAST_MATCH:
+ sub = &res->lastMatch;
+ break;
+ case REGEXP_STATIC_LAST_PAREN:
+ sub = &res->lastParen;
+ break;
+ case REGEXP_STATIC_LEFT_CONTEXT:
+ sub = &res->leftContext;
+ break;
+ case REGEXP_STATIC_RIGHT_CONTEXT:
+ sub = &res->rightContext;
+ break;
+ default:
+ sub = REGEXP_PAREN_SUBSTRING(res, slot);
+ break;
+ }
+ str = js_NewStringCopyN(cx, sub->chars, sub->length, 0);
+ if (!str)
+ return JS_FALSE;
+ *vp = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+regexp_static_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSRegExpStatics *res;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ res = &cx->regExpStatics;
+ /* XXX use if-else rather than switch to keep MSVC1.52 from crashing */
+ if (JSVAL_TO_INT(id) == REGEXP_STATIC_INPUT) {
+ if (!JSVAL_IS_STRING(*vp) &&
+ !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
+ return JS_FALSE;
+ }
+ res->input = JSVAL_TO_STRING(*vp);
+ } else if (JSVAL_TO_INT(id) == REGEXP_STATIC_MULTILINE) {
+ if (!JSVAL_IS_BOOLEAN(*vp) &&
+ !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) {
+ return JS_FALSE;
+ }
+ res->multiline = JSVAL_TO_BOOLEAN(*vp);
+ }
+ return JS_TRUE;
+}
+
+static JSPropertySpec regexp_static_props[] = {
+ {"input",
+ REGEXP_STATIC_INPUT,
+ JSPROP_ENUMERATE|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_setProperty},
+ {"multiline",
+ REGEXP_STATIC_MULTILINE,
+ JSPROP_ENUMERATE|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_setProperty},
+ {"lastMatch",
+ REGEXP_STATIC_LAST_MATCH,
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"lastParen",
+ REGEXP_STATIC_LAST_PAREN,
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"leftContext",
+ REGEXP_STATIC_LEFT_CONTEXT,
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"rightContext",
+ REGEXP_STATIC_RIGHT_CONTEXT,
+ JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+
+ /* XXX should have block scope and local $1, etc. */
+ {"$1", 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$2", 1, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$3", 2, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$4", 3, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$5", 4, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$6", 5, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$7", 6, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$8", 7, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+ {"$9", 8, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED,
+ regexp_static_getProperty, regexp_static_getProperty},
+
+ {0,0,0,0,0}
+};
+
+static void
+regexp_finalize(JSContext *cx, JSObject *obj)
+{
+ JSRegExp *re;
+
+ re = (JSRegExp *) JS_GetPrivate(cx, obj);
+ if (!re)
+ return;
+ js_DestroyRegExp(cx, re);
+}
+
+/* Forward static prototype. */
+static JSBool
+regexp_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+static JSBool
+regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return regexp_exec(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
+}
+
+#if JS_HAS_XDR
+
+#include "jsxdrapi.h"
+
+static JSBool
+regexp_xdrObject(JSXDRState *xdr, JSObject **objp)
+{
+ JSRegExp *re;
+ JSString *source;
+ uint8 flags;
+
+ if (xdr->mode == JSXDR_ENCODE) {
+ re = (JSRegExp *) JS_GetPrivate(xdr->cx, *objp);
+ if (!re)
+ return JS_FALSE;
+ source = re->source;
+ flags = (uint8) re->flags;
+ }
+ if (!JS_XDRString(xdr, &source) ||
+ !JS_XDRUint8(xdr, &flags)) {
+ return JS_FALSE;
+ }
+ if (xdr->mode == JSXDR_DECODE) {
+ *objp = js_NewObject(xdr->cx, &js_RegExpClass, NULL, NULL);
+ if (!*objp)
+ return JS_FALSE;
+ re = js_NewRegExp(xdr->cx, NULL, source, flags, JS_FALSE);
+ if (!re)
+ return JS_FALSE;
+ if (!JS_SetPrivate(xdr->cx, *objp, re) ||
+ !js_SetLastIndex(xdr->cx, *objp, 0)) {
+ js_DestroyRegExp(xdr->cx, re);
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+#else /* !JS_HAS_XDR */
+
+#define regexp_xdrObject NULL
+
+#endif /* !JS_HAS_XDR */
+
+static uint32
+regexp_mark(JSContext *cx, JSObject *obj, void *arg)
+{
+ JSRegExp *re = (JSRegExp *) JS_GetPrivate(cx, obj);
+ if (re)
+ JS_MarkGCThing(cx, re->source, "source", arg);
+ return 0;
+}
+
+JSClass js_RegExpClass = {
+ js_RegExp_str,
+ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
+ JS_PropertyStub, JS_PropertyStub, regexp_getProperty, regexp_setProperty,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, regexp_finalize,
+ NULL, NULL, regexp_call, NULL,
+ regexp_xdrObject, NULL, regexp_mark, 0
+};
+
+static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0};
+
+static JSBool
+regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSRegExp *re;
+ const jschar *source;
+ jschar *chars;
+ size_t length, nflags;
+ uintN flags;
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv))
+ return JS_FALSE;
+ JS_LOCK_OBJ(cx, obj);
+ re = (JSRegExp *) JS_GetPrivate(cx, obj);
+ if (!re) {
+ JS_UNLOCK_OBJ(cx, obj);
+ *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
+ return JS_TRUE;
+ }
+
+ source = JSSTRING_CHARS(re->source);
+ length = JSSTRING_LENGTH(re->source);
+ if (length == 0) {
+ source = empty_regexp_ucstr;
+ length = sizeof(empty_regexp_ucstr) / sizeof(jschar) - 1;
+ }
+ length += 2;
+ nflags = 0;
+ for (flags = re->flags; flags != 0; flags &= flags - 1)
+ nflags++;
+ chars = (jschar*) JS_malloc(cx, (length + nflags + 1) * sizeof(jschar));
+ if (!chars) {
+ JS_UNLOCK_OBJ(cx, obj);
+ return JS_FALSE;
+ }
+
+ chars[0] = '/';
+ js_strncpy(&chars[1], source, length - 2);
+ chars[length-1] = '/';
+ if (nflags) {
+ if (re->flags & JSREG_GLOB)
+ chars[length++] = 'g';
+ if (re->flags & JSREG_FOLD)
+ chars[length++] = 'i';
+ if (re->flags & JSREG_MULTILINE)
+ chars[length++] = 'm';
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+ chars[length] = 0;
+
+ str = js_NewString(cx, chars, length, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+regexp_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *opt, *str;
+ JSRegExp *oldre, *re;
+ JSBool ok;
+ JSObject *obj2;
+
+ if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv))
+ return JS_FALSE;
+ opt = NULL;
+ if (argc == 0) {
+ str = cx->runtime->emptyString;
+ } else {
+ if (JSVAL_IS_OBJECT(argv[0])) {
+ /*
+ * If we get passed in a RegExp object we construct a new
+ * RegExp that is a duplicate of it by re-compiling the
+ * original source code. ECMA requires that it be an error
+ * here if the flags are specified. (We must use the flags
+ * from the original RegExp also).
+ */
+ obj2 = JSVAL_TO_OBJECT(argv[0]);
+ if (obj2 && OBJ_GET_CLASS(cx, obj2) == &js_RegExpClass) {
+ if (argc >= 2 && !JSVAL_IS_VOID(argv[1])) { /* 'flags' passed */
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_NEWREGEXP_FLAGGED);
+ return JS_FALSE;
+ }
+ JS_LOCK_OBJ(cx, obj2);
+ re = (JSRegExp *) JS_GetPrivate(cx, obj2);
+ if (!re) {
+ JS_UNLOCK_OBJ(cx, obj2);
+ return JS_FALSE;
+ }
+ re = js_NewRegExp(cx, NULL, re->source, re->flags, JS_FALSE);
+ JS_UNLOCK_OBJ(cx, obj2);
+ goto madeit;
+ }
+ }
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str);
+ if (argc > 1) {
+ if (JSVAL_IS_VOID(argv[1])) {
+ opt = NULL;
+ } else {
+ opt = js_ValueToString(cx, argv[1]);
+ if (!opt)
+ return JS_FALSE;
+ argv[1] = STRING_TO_JSVAL(opt);
+ }
+ }
+ }
+ re = js_NewRegExpOpt(cx, NULL, str, opt, JS_FALSE);
+madeit:
+ if (!re)
+ return JS_FALSE;
+ JS_LOCK_OBJ(cx, obj);
+ oldre = (JSRegExp *) JS_GetPrivate(cx, obj);
+ ok = JS_SetPrivate(cx, obj, re) && js_SetLastIndex(cx, obj, 0);
+ JS_UNLOCK_OBJ(cx, obj);
+ if (!ok) {
+ js_DestroyRegExp(cx, re);
+ } else {
+ if (oldre)
+ js_DestroyRegExp(cx, oldre);
+ *rval = OBJECT_TO_JSVAL(obj);
+ }
+ return ok;
+}
+
+static JSBool
+regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ JSBool test, jsval *rval)
+{
+ JSBool ok;
+ JSRegExp *re;
+ jsdouble lastIndex;
+ JSString *str;
+ size_t i;
+
+ ok = JS_InstanceOf(cx, obj, &js_RegExpClass, argv);
+ if (!ok)
+ return JS_FALSE;
+ JS_LOCK_OBJ(cx, obj);
+ re = (JSRegExp *) JS_GetPrivate(cx, obj);
+ if (!re) {
+ JS_UNLOCK_OBJ(cx, obj);
+ return JS_TRUE;
+ }
+
+ /* NB: we must reach out: after this paragraph, in order to drop re. */
+ HOLD_REGEXP(cx, re);
+ if (re->flags & JSREG_GLOB) {
+ ok = js_GetLastIndex(cx, obj, &lastIndex);
+ } else {
+ lastIndex = 0;
+ }
+ JS_UNLOCK_OBJ(cx, obj);
+ if (!ok)
+ goto out;
+
+ /* Now that obj is unlocked, it's safe to (potentially) grab the GC lock. */
+ if (argc == 0) {
+ str = cx->regExpStatics.input;
+ if (!str) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_NO_INPUT,
+ JS_GetStringBytes(re->source),
+ (re->flags & JSREG_GLOB) ? "g" : "",
+ (re->flags & JSREG_FOLD) ? "i" : "",
+ (re->flags & JSREG_MULTILINE) ? "m" : "");
+ ok = JS_FALSE;
+ goto out;
+ }
+ } else {
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ goto out;
+ argv[0] = STRING_TO_JSVAL(str);
+ }
+
+ if (lastIndex < 0 || JSSTRING_LENGTH(str) < lastIndex) {
+ ok = js_SetLastIndex(cx, obj, 0);
+ *rval = JSVAL_NULL;
+ } else {
+ i = (size_t) lastIndex;
+ ok = js_ExecuteRegExp(cx, re, str, &i, test, rval);
+ if (ok && (re->flags & JSREG_GLOB))
+ ok = js_SetLastIndex(cx, obj, (*rval == JSVAL_NULL) ? 0 : i);
+ }
+
+out:
+ DROP_REGEXP(cx, re);
+ return ok;
+}
+
+static JSBool
+regexp_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return regexp_exec_sub(cx, obj, argc, argv, JS_FALSE, rval);
+}
+
+static JSBool
+regexp_test(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (!regexp_exec_sub(cx, obj, argc, argv, JS_TRUE, rval))
+ return JS_FALSE;
+ if (*rval != JSVAL_TRUE)
+ *rval = JSVAL_FALSE;
+ return JS_TRUE;
+}
+
+static JSFunctionSpec regexp_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, regexp_toString, 0,0,0},
+#endif
+ {js_toString_str, regexp_toString, 0,0,0},
+ {"compile", regexp_compile, 1,0,0},
+ {"exec", regexp_exec, 0,0,0},
+ {"test", regexp_test, 0,0,0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ /*
+ * If first arg is regexp and no flags are given, just return the arg.
+ * (regexp_compile detects the regexp + flags case and throws a
+ * TypeError.) See 10.15.3.1.
+ */
+ if ((argc < 2 || JSVAL_IS_VOID(argv[1])) && JSVAL_IS_OBJECT(argv[0]) &&
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[0])) == &js_RegExpClass) {
+ *rval = argv[0];
+ return JS_TRUE;
+ }
+
+ /* Otherwise, replace obj with a new RegExp object. */
+ obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ }
+ return regexp_compile(cx, obj, argc, argv, rval);
+}
+
+JSObject *
+js_InitRegExpClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto, *ctor;
+ jsval rval;
+
+ proto = JS_InitClass(cx, obj, NULL, &js_RegExpClass, RegExp, 1,
+ regexp_props, regexp_methods,
+ regexp_static_props, NULL);
+
+ if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
+ return NULL;
+ if (!JS_AliasProperty(cx, ctor, "input", "$_") ||
+ !JS_AliasProperty(cx, ctor, "multiline", "$*") ||
+ !JS_AliasProperty(cx, ctor, "lastMatch", "$&") ||
+ !JS_AliasProperty(cx, ctor, "lastParen", "$+") ||
+ !JS_AliasProperty(cx, ctor, "leftContext", "$`") ||
+ !JS_AliasProperty(cx, ctor, "rightContext", "$'")) {
+ goto bad;
+ }
+
+ /* Give RegExp.prototype private data so it matches the empty string. */
+ if (!regexp_compile(cx, proto, 0, NULL, &rval))
+ goto bad;
+ return proto;
+
+bad:
+ JS_DeleteProperty(cx, obj, js_RegExpClass.name);
+ return NULL;
+}
+
+JSObject *
+js_NewRegExpObject(JSContext *cx, JSTokenStream *ts,
+ jschar *chars, size_t length, uintN flags)
+{
+ JSString *str;
+ JSObject *obj;
+ JSRegExp *re;
+
+ str = js_NewStringCopyN(cx, chars, length, 0);
+ if (!str)
+ return NULL;
+ re = js_NewRegExp(cx, ts, str, flags, JS_FALSE);
+ if (!re)
+ return NULL;
+ obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
+ if (!obj || !JS_SetPrivate(cx, obj, re) || !js_SetLastIndex(cx, obj, 0)) {
+ js_DestroyRegExp(cx, re);
+ return NULL;
+ }
+ return obj;
+}
+
+JSObject *
+js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent)
+{
+ JSObject *clone;
+ JSRegExp *re;
+
+ JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
+ clone = js_NewObject(cx, &js_RegExpClass, NULL, parent);
+ if (!clone)
+ return NULL;
+ re = JS_GetPrivate(cx, obj);
+ if (!JS_SetPrivate(cx, clone, re) || !js_SetLastIndex(cx, clone, 0)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ HOLD_REGEXP(cx, re);
+ return clone;
+}
+
+JSBool
+js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex)
+{
+ jsval v;
+
+ return JS_GetReservedSlot(cx, obj, 0, &v) &&
+ js_ValueToNumber(cx, v, lastIndex);
+}
+
+JSBool
+js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex)
+{
+ jsval v;
+
+ return js_NewNumberValue(cx, lastIndex, &v) &&
+ JS_SetReservedSlot(cx, obj, 0, v);
+}
+
+#endif /* JS_HAS_REGEXPS */
diff --git a/src/dom/js/jsregexp.h b/src/dom/js/jsregexp.h
new file mode 100644
index 000000000..0485c2860
--- /dev/null
+++ b/src/dom/js/jsregexp.h
@@ -0,0 +1,168 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsregexp_h___
+#define jsregexp_h___
+/*
+ * JS regular expression interface.
+ */
+#include <stddef.h>
+#include "jspubtd.h"
+#include "jsstr.h"
+
+#ifdef JS_THREADSAFE
+#include "jsdhash.h"
+#endif
+
+struct JSRegExpStatics {
+ JSString *input; /* input string to match (perl $_, GC root) */
+ JSBool multiline; /* whether input contains newlines (perl $*) */
+ uintN parenCount; /* number of valid elements in parens[] */
+ uintN moreLength; /* number of allocated elements in moreParens */
+ JSSubString parens[9]; /* last set of parens matched (perl $1, $2) */
+ JSSubString *moreParens; /* null or realloc'd vector for $10, etc. */
+ JSSubString lastMatch; /* last string matched (perl $&) */
+ JSSubString lastParen; /* last paren matched (perl $+) */
+ JSSubString leftContext; /* input to left of last match (perl $`) */
+ JSSubString rightContext; /* input to right of last match (perl $') */
+};
+
+/*
+ * This struct holds a bitmap representation of a class from a regexp.
+ * There's a list of these referenced by the classList field in the JSRegExp
+ * struct below. The initial state has startIndex set to the offset in the
+ * original regexp source of the beginning of the class contents. The first
+ * use of the class converts the source representation into a bitmap.
+ *
+ */
+typedef struct RECharSet {
+ JSBool converted;
+ JSBool sense;
+ uint16 length;
+ union {
+ uint8 *bits;
+ struct {
+ uint16 startIndex;
+ uint16 length;
+ } src;
+ } u;
+} RECharSet;
+
+/*
+ * This macro is safe because moreParens is guaranteed to be allocated and big
+ * enough to hold parenCount, or else be null when parenCount is 0.
+ */
+#define REGEXP_PAREN_SUBSTRING(res, num) \
+ (((jsuint)(num) < (jsuint)(res)->parenCount) \
+ ? ((jsuint)(num) < 9) \
+ ? &(res)->parens[num] \
+ : &(res)->moreParens[(num) - 9] \
+ : &js_EmptySubString)
+
+typedef struct RENode RENode;
+
+struct JSRegExp {
+ jsrefcount nrefs; /* reference count */
+ uint32 parenCount:24, /* number of parenthesized submatches */
+ flags:8; /* flags, see jsapi.h's JSREG_* defines */
+ uint32 classCount; /* count [...] bitmaps */
+ RECharSet *classList; /* list of [...] bitmaps */
+ JSString *source; /* locked source string, sans // */
+ jsbytecode program[1]; /* regular expression bytecode */
+};
+
+extern JSRegExp *
+js_NewRegExp(JSContext *cx, JSTokenStream *ts,
+ JSString *str, uintN flags, JSBool flat);
+
+extern JSRegExp *
+js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts,
+ JSString *str, JSString *opt, JSBool flat);
+
+extern void
+js_DestroyRegExp(JSContext *cx, JSRegExp *re);
+
+/*
+ * Execute re on input str at *indexp, returning null in *rval on mismatch.
+ * On match, return true if test is true, otherwise return an array object.
+ * Update *indexp and cx->regExpStatics always on match.
+ */
+extern JSBool
+js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
+ JSBool test, jsval *rval);
+
+/*
+ * These two add and remove GC roots, respectively, so their calls must be
+ * well-ordered.
+ */
+extern JSBool
+js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res);
+
+extern void
+js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res);
+
+#define JSVAL_IS_REGEXP(cx, v) \
+ (JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) && \
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_RegExpClass)
+
+extern JSClass js_RegExpClass;
+
+extern JSObject *
+js_InitRegExpClass(JSContext *cx, JSObject *obj);
+
+/*
+ * Create a new RegExp object.
+ */
+extern JSObject *
+js_NewRegExpObject(JSContext *cx, JSTokenStream *ts,
+ jschar *chars, size_t length, uintN flags);
+
+extern JSBool
+js_XDRRegExp(JSXDRState *xdr, JSObject **objp);
+
+extern JSObject *
+js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent);
+
+extern JSBool
+js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex);
+
+extern JSBool
+js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex);
+
+#endif /* jsregexp_h___ */
diff --git a/src/dom/js/jsscan.c b/src/dom/js/jsscan.c
new file mode 100644
index 000000000..e0bc5cd92
--- /dev/null
+++ b/src/dom/js/jsscan.c
@@ -0,0 +1,1315 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS lexical scanner.
+ */
+#include "jsstddef.h"
+#include <stdio.h> /* first to avoid trouble on some systems */
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h" /* Added by JSIFY */
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsdtoa.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsemit.h"
+#include "jsexn.h"
+#include "jsnum.h"
+#include "jsopcode.h"
+#include "jsregexp.h"
+#include "jsscan.h"
+
+#define RESERVE_JAVA_KEYWORDS
+#define RESERVE_ECMA_KEYWORDS
+
+static struct keyword {
+ const char *name;
+ JSTokenType tokentype; /* JSTokenType */
+ JSOp op; /* JSOp */
+ JSVersion version; /* JSVersion */
+} keywords[] = {
+ {"break", TOK_BREAK, JSOP_NOP, JSVERSION_DEFAULT},
+ {"case", TOK_CASE, JSOP_NOP, JSVERSION_DEFAULT},
+ {"continue", TOK_CONTINUE, JSOP_NOP, JSVERSION_DEFAULT},
+ {"default", TOK_DEFAULT, JSOP_NOP, JSVERSION_DEFAULT},
+ {js_delete_str, TOK_DELETE, JSOP_NOP, JSVERSION_DEFAULT},
+ {"do", TOK_DO, JSOP_NOP, JSVERSION_DEFAULT},
+ {"else", TOK_ELSE, JSOP_NOP, JSVERSION_DEFAULT},
+ {"export", TOK_EXPORT, JSOP_NOP, JSVERSION_1_2},
+ {js_false_str, TOK_PRIMARY, JSOP_FALSE, JSVERSION_DEFAULT},
+ {"for", TOK_FOR, JSOP_NOP, JSVERSION_DEFAULT},
+ {js_function_str, TOK_FUNCTION, JSOP_NOP, JSVERSION_DEFAULT},
+ {"if", TOK_IF, JSOP_NOP, JSVERSION_DEFAULT},
+ {js_in_str, TOK_IN, JSOP_IN, JSVERSION_DEFAULT},
+ {js_new_str, TOK_NEW, JSOP_NEW, JSVERSION_DEFAULT},
+ {js_null_str, TOK_PRIMARY, JSOP_NULL, JSVERSION_DEFAULT},
+ {"return", TOK_RETURN, JSOP_NOP, JSVERSION_DEFAULT},
+ {"switch", TOK_SWITCH, JSOP_NOP, JSVERSION_DEFAULT},
+ {js_this_str, TOK_PRIMARY, JSOP_THIS, JSVERSION_DEFAULT},
+ {js_true_str, TOK_PRIMARY, JSOP_TRUE, JSVERSION_DEFAULT},
+ {js_typeof_str, TOK_UNARYOP, JSOP_TYPEOF,JSVERSION_DEFAULT},
+ {"var", TOK_VAR, JSOP_DEFVAR,JSVERSION_DEFAULT},
+ {js_void_str, TOK_UNARYOP, JSOP_VOID, JSVERSION_DEFAULT},
+ {"while", TOK_WHILE, JSOP_NOP, JSVERSION_DEFAULT},
+ {"with", TOK_WITH, JSOP_NOP, JSVERSION_DEFAULT},
+
+#if JS_HAS_CONST
+ {js_const_str, TOK_VAR, JSOP_DEFCONST,JSVERSION_DEFAULT},
+#else
+ {js_const_str, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+#endif
+
+#if JS_HAS_EXCEPTIONS
+ {"try", TOK_TRY, JSOP_NOP, JSVERSION_DEFAULT},
+ {"catch", TOK_CATCH, JSOP_NOP, JSVERSION_DEFAULT},
+ {"finally", TOK_FINALLY, JSOP_NOP, JSVERSION_DEFAULT},
+ {"throw", TOK_THROW, JSOP_NOP, JSVERSION_DEFAULT},
+#else
+ {"try", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"catch", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"finally", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"throw", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+#endif
+
+#if JS_HAS_INSTANCEOF
+ {js_instanceof_str, TOK_INSTANCEOF, JSOP_INSTANCEOF,JSVERSION_1_4},
+#else
+ {js_instanceof_str, TOK_RESERVED, JSOP_NOP, JSVERSION_1_4},
+#endif
+
+#ifdef RESERVE_JAVA_KEYWORDS
+ {"abstract", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"boolean", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"byte", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"char", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"class", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"double", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"extends", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"final", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"float", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"goto", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"implements", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"import", TOK_IMPORT, JSOP_NOP, JSVERSION_DEFAULT},
+ {"int", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"interface", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"long", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"native", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"package", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"private", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"protected", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"public", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"short", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"static", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"super", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"synchronized", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"throws", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"transient", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+ {"volatile", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},
+#endif
+
+#ifdef RESERVE_ECMA_KEYWORDS
+ {"enum", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},
+#endif
+
+#if JS_HAS_DEBUGGER_KEYWORD
+ {"debugger", TOK_DEBUGGER, JSOP_NOP, JSVERSION_1_3},
+#elif defined(RESERVE_ECMA_KEYWORDS)
+ {"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},
+#endif
+ {0, TOK_EOF, JSOP_NOP, JSVERSION_DEFAULT}
+};
+
+JSBool
+js_InitScanner(JSContext *cx)
+{
+ struct keyword *kw;
+ JSAtom *atom;
+
+ for (kw = keywords; kw->name; kw++) {
+ atom = js_Atomize(cx, kw->name, strlen(kw->name), ATOM_PINNED);
+ if (!atom)
+ return JS_FALSE;
+ ATOM_SET_KEYWORD(atom, kw);
+ }
+ return JS_TRUE;
+}
+
+JS_FRIEND_API(void)
+js_MapKeywords(void (*mapfun)(const char *))
+{
+ struct keyword *kw;
+
+ for (kw = keywords; kw->name; kw++)
+ mapfun(kw->name);
+}
+
+JSTokenStream *
+js_NewTokenStream(JSContext *cx, const jschar *base, size_t length,
+ const char *filename, uintN lineno,
+ JSPrincipals *principals)
+{
+ JSTokenStream *ts;
+
+ ts = js_NewBufferTokenStream(cx, base, length);
+ if (!ts)
+ return NULL;
+ ts->filename = filename;
+ ts->lineno = lineno;
+ if (principals)
+ JSPRINCIPALS_HOLD(cx, principals);
+ ts->principals = principals;
+ return ts;
+}
+
+JS_FRIEND_API(JSTokenStream *)
+js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length)
+{
+ size_t nb;
+ JSTokenStream *ts;
+
+ nb = sizeof(JSTokenStream) + JS_LINE_LIMIT * sizeof(jschar);
+ JS_ARENA_ALLOCATE_CAST(ts, JSTokenStream *, &cx->tempPool, nb);
+ if (!ts) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ memset(ts, 0, nb);
+ ts->lineno = 1;
+ ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = (jschar *)(ts + 1);
+ ts->userbuf.base = (jschar *)base;
+ ts->userbuf.limit = (jschar *)base + length;
+ ts->userbuf.ptr = (jschar *)base;
+ ts->listener = cx->runtime->sourceHandler;
+ ts->listenerData = cx->runtime->sourceHandlerData;
+ return ts;
+}
+
+JS_FRIEND_API(JSTokenStream *)
+js_NewFileTokenStream(JSContext *cx, const char *filename, FILE *defaultfp)
+{
+ jschar *base;
+ JSTokenStream *ts;
+ FILE *file;
+
+ JS_ARENA_ALLOCATE_CAST(base, jschar *, &cx->tempPool,
+ JS_LINE_LIMIT * sizeof(jschar));
+ if (!base)
+ return NULL;
+ ts = js_NewBufferTokenStream(cx, base, JS_LINE_LIMIT);
+ if (!ts)
+ return NULL;
+ if (!filename || strcmp(filename, "-") == 0) {
+ file = defaultfp;
+ } else {
+ file = fopen(filename, "r");
+ if (!file) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
+ filename, "No such file or directory");
+ return NULL;
+ }
+ }
+ ts->userbuf.ptr = ts->userbuf.limit;
+ ts->file = file;
+ ts->filename = filename;
+ return ts;
+}
+
+JS_FRIEND_API(JSBool)
+js_CloseTokenStream(JSContext *cx, JSTokenStream *ts)
+{
+ if (ts->principals)
+ JSPRINCIPALS_DROP(cx, ts->principals);
+ return !ts->file || fclose(ts->file) == 0;
+}
+
+static int
+my_fgets(char *buf, int size, FILE *file)
+{
+ int n, i, c;
+ JSBool crflag;
+
+ n = size - 1;
+ if (n < 0)
+ return -1;
+
+ crflag = JS_FALSE;
+ for (i = 0; i < n && (c = getc(file)) != EOF; i++) {
+ buf[i] = c;
+ if (c == '\n') { /* any \n ends a line */
+ i++; /* keep the \n; we know there is room for \0 */
+ break;
+ }
+ if (crflag) { /* \r not followed by \n ends line at the \r */
+ ungetc(c, file);
+ break; /* and overwrite c in buf with \0 */
+ }
+ crflag = (c == '\r');
+ }
+
+ buf[i] = '\0';
+ return i;
+}
+
+static int32
+GetChar(JSTokenStream *ts)
+{
+ int32 c;
+ ptrdiff_t i, j, len, olen;
+ JSBool crflag;
+ char cbuf[JS_LINE_LIMIT];
+ jschar *ubuf, *nl;
+
+ if (ts->ungetpos != 0) {
+ c = ts->ungetbuf[--ts->ungetpos];
+ } else {
+ do {
+ if (ts->linebuf.ptr == ts->linebuf.limit) {
+ len = PTRDIFF(ts->userbuf.limit, ts->userbuf.ptr, jschar);
+ if (len <= 0) {
+ if (!ts->file) {
+ ts->flags |= TSF_EOF;
+ return EOF;
+ }
+
+ /* Fill ts->userbuf so that \r and \r\n convert to \n. */
+ crflag = (ts->flags & TSF_CRFLAG) != 0;
+ len = my_fgets(cbuf, JS_LINE_LIMIT - crflag, ts->file);
+ if (len <= 0) {
+ ts->flags |= TSF_EOF;
+ return EOF;
+ }
+ olen = len;
+ ubuf = ts->userbuf.base;
+ i = 0;
+ if (crflag) {
+ ts->flags &= ~TSF_CRFLAG;
+ if (cbuf[0] != '\n') {
+ ubuf[i++] = '\n';
+ len++;
+ ts->linepos--;
+ }
+ }
+ for (j = 0; i < len; i++, j++)
+ ubuf[i] = (jschar) (unsigned char) cbuf[j];
+ ts->userbuf.limit = ubuf + len;
+ ts->userbuf.ptr = ubuf;
+ }
+ if (ts->listener) {
+ ts->listener(ts->filename, ts->lineno, ts->userbuf.ptr, len,
+ &ts->listenerTSData, ts->listenerData);
+ }
+
+ /*
+ * Any one of \n, \r, or \r\n ends a line (longest match wins).
+ * Also allow the Unicode line and paragraph separators.
+ */
+ for (nl = ts->userbuf.ptr; nl < ts->userbuf.limit; nl++) {
+ /*
+ * Try to prevent value-testing on most characters by
+ * filtering out characters that aren't 000x or 202x.
+ */
+ if ((*nl & 0xDFD0) == 0) {
+ if (*nl == '\n')
+ break;
+ if (*nl == '\r') {
+ if (nl + 1 < ts->userbuf.limit && nl[1] == '\n')
+ nl++;
+ break;
+ }
+ if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR)
+ break;
+ }
+ }
+
+ /*
+ * If there was a line terminator, copy thru it into linebuf.
+ * Else copy JS_LINE_LIMIT-1 bytes into linebuf.
+ */
+ if (nl < ts->userbuf.limit)
+ len = PTRDIFF(nl, ts->userbuf.ptr, jschar) + 1;
+ if (len >= JS_LINE_LIMIT)
+ len = JS_LINE_LIMIT - 1;
+ js_strncpy(ts->linebuf.base, ts->userbuf.ptr, len);
+ ts->userbuf.ptr += len;
+ olen = len;
+
+ /*
+ * Make sure linebuf contains \n for EOL (don't do this in
+ * userbuf because the user's string might be readonly).
+ */
+ if (nl < ts->userbuf.limit) {
+ if (*nl == '\r') {
+ if (ts->linebuf.base[len-1] == '\r') {
+ /*
+ * Does the line segment end in \r? We must check
+ * for a \n at the front of the next segment before
+ * storing a \n into linebuf. This case matters
+ * only when we're reading from a file.
+ */
+ if (nl + 1 == ts->userbuf.limit && ts->file) {
+ len--;
+ ts->flags |= TSF_CRFLAG; /* clear NLFLAG? */
+ if (len == 0) {
+ /*
+ * This can happen when a segment ends in
+ * \r\r. Start over. ptr == limit in this
+ * case, so we'll fall into buffer-filling
+ * code.
+ */
+ return GetChar(ts);
+ }
+ } else {
+ ts->linebuf.base[len-1] = '\n';
+ }
+ }
+ } else if (*nl == '\n') {
+ if (nl > ts->userbuf.base &&
+ nl[-1] == '\r' &&
+ ts->linebuf.base[len-2] == '\r') {
+ len--;
+ JS_ASSERT(ts->linebuf.base[len] == '\n');
+ ts->linebuf.base[len-1] = '\n';
+ }
+ } else if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR) {
+ ts->linebuf.base[len-1] = '\n';
+ }
+ }
+
+ /* Reset linebuf based on adjusted segment length. */
+ ts->linebuf.limit = ts->linebuf.base + len;
+ ts->linebuf.ptr = ts->linebuf.base;
+
+ /* Update position of linebuf within physical userbuf line. */
+ if (!(ts->flags & TSF_NLFLAG))
+ ts->linepos += ts->linelen;
+ else
+ ts->linepos = 0;
+ if (ts->linebuf.limit[-1] == '\n')
+ ts->flags |= TSF_NLFLAG;
+ else
+ ts->flags &= ~TSF_NLFLAG;
+
+ /* Update linelen from original segment length. */
+ ts->linelen = olen;
+ }
+ c = *ts->linebuf.ptr++;
+ } while (JS_ISFORMAT(c));
+ }
+ if (c == '\n')
+ ts->lineno++;
+ return c;
+}
+
+static void
+UngetChar(JSTokenStream *ts, int32 c)
+{
+ if (c == EOF)
+ return;
+ JS_ASSERT(ts->ungetpos < sizeof ts->ungetbuf / sizeof ts->ungetbuf[0]);
+ if (c == '\n')
+ ts->lineno--;
+ ts->ungetbuf[ts->ungetpos++] = (jschar)c;
+}
+
+static int32
+PeekChar(JSTokenStream *ts)
+{
+ int32 c;
+
+ c = GetChar(ts);
+ UngetChar(ts, c);
+ return c;
+}
+
+static JSBool
+PeekChars(JSTokenStream *ts, intN n, jschar *cp)
+{
+ intN i, j;
+ int32 c;
+
+ for (i = 0; i < n; i++) {
+ c = GetChar(ts);
+ if (c == EOF)
+ break;
+ cp[i] = (jschar)c;
+ }
+ for (j = i - 1; j >= 0; j--)
+ UngetChar(ts, cp[j]);
+ return i == n;
+}
+
+static void
+SkipChars(JSTokenStream *ts, intN n)
+{
+ while (--n >= 0)
+ GetChar(ts);
+}
+
+static JSBool
+MatchChar(JSTokenStream *ts, int32 expect)
+{
+ int32 c;
+
+ c = GetChar(ts);
+ if (c == expect)
+ return JS_TRUE;
+ UngetChar(ts, c);
+ return JS_FALSE;
+}
+
+JSBool
+js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts,
+ JSCodeGenerator *cg, uintN flags,
+ const uintN errorNumber, ...)
+{
+ va_list ap;
+ JSErrorReporter onError;
+ JSErrorReport report;
+ jschar *tokenptr;
+ JSString *linestr = NULL;
+ char *message;
+ JSBool warning;
+
+ if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
+ return JS_TRUE;
+
+ memset(&report, 0, sizeof (struct JSErrorReport));
+ report.flags = flags;
+ report.errorNumber = errorNumber;
+ message = NULL;
+
+ va_start(ap, errorNumber);
+ if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL,
+ errorNumber, &message, &report, &warning,
+ JS_TRUE, ap)) {
+ return JS_FALSE;
+ }
+ va_end(ap);
+
+ js_AddRoot(cx, &linestr, "error line buffer");
+
+ JS_ASSERT(!ts || ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT);
+ onError = cx->errorReporter;
+ if (onError) {
+ /*
+ * We are typically called with non-null ts and null cg from jsparse.c.
+ * We can be called with null ts from the regexp compilation functions.
+ * The code generator (jsemit.c) may pass null ts and non-null cg.
+ */
+ if (ts) {
+ report.filename = ts->filename;
+ report.lineno = ts->lineno;
+ linestr = js_NewStringCopyN(cx, ts->linebuf.base,
+ ts->linebuf.limit - ts->linebuf.base,
+ 0);
+ report.linebuf = linestr
+ ? JS_GetStringBytes(linestr)
+ : NULL;
+ tokenptr =
+ ts->tokens[(ts->cursor + ts->lookahead) & NTOKENS_MASK].ptr;
+ report.tokenptr = linestr
+ ? report.linebuf + (tokenptr - ts->linebuf.base)
+ : NULL;
+ report.uclinebuf = linestr
+ ? JS_GetStringChars(linestr)
+ : NULL;
+ report.uctokenptr = linestr
+ ? report.uclinebuf + (tokenptr - ts->linebuf.base)
+ : NULL;
+ } else if (cg) {
+ report.filename = cg->filename;
+ report.lineno = CG_CURRENT_LINE(cg);
+ }
+
+#if JS_HAS_ERROR_EXCEPTIONS
+ /*
+ * If there's a runtime exception type associated with this error
+ * number, set that as the pending exception. For errors occuring at
+ * compile time, this is very likely to be a JSEXN_SYNTAXERR.
+ *
+ * If an exception is thrown but not caught, the JSREPORT_EXCEPTION
+ * flag will be set in report.flags. Proper behavior for an error
+ * reporter is to ignore a report with this flag for all but top-level
+ * compilation errors. The exception will remain pending, and so long
+ * as the non-top-level "load", "eval", or "compile" native function
+ * returns false, the top-level reporter will eventually receive the
+ * uncaught exception report.
+ *
+ * XXX it'd probably be best if there was only one call to this
+ * function, but there seem to be two error reporter call points.
+ */
+
+ /*
+ * Only try to raise an exception if there isn't one already set -
+ * otherwise the exception will describe only the last compile error,
+ * which is likely spurious.
+ */
+ if (!(ts && (ts->flags & TSF_ERROR)))
+ if (js_ErrorToException(cx, message, &report))
+ onError = NULL;
+
+ /*
+ * Suppress any compiletime errors that don't occur at the top level.
+ * This may still fail, as interplevel may be zero in contexts where we
+ * don't really want to call the error reporter, as when js is called
+ * by other code which could catch the error.
+ */
+ if (cx->interpLevel != 0)
+ onError = NULL;
+#endif
+ if (cx->runtime->debugErrorHook && onError) {
+ JSDebugErrorHook hook = cx->runtime->debugErrorHook;
+ /* test local in case debugErrorHook changed on another thread */
+ if (hook && !hook(cx, message, &report,
+ cx->runtime->debugErrorHookData)) {
+ onError = NULL;
+ }
+ }
+ if (onError)
+ (*onError)(cx, message, &report);
+ }
+ if (message)
+ JS_free(cx, message);
+ if (report.messageArgs) {
+ int i = 0;
+ while (report.messageArgs[i])
+ JS_free(cx, (void *)report.messageArgs[i++]);
+ JS_free(cx, (void *)report.messageArgs);
+ }
+ if (report.ucmessage)
+ JS_free(cx, (void *)report.ucmessage);
+
+ js_RemoveRoot(cx->runtime, &linestr);
+
+ if (ts && !JSREPORT_IS_WARNING(flags)) {
+ /* Set the error flag to suppress spurious reports. */
+ ts->flags |= TSF_ERROR;
+ }
+ return warning;
+}
+
+JSTokenType
+js_PeekToken(JSContext *cx, JSTokenStream *ts)
+{
+ JSTokenType tt;
+
+ if (ts->lookahead != 0) {
+ tt = ts->tokens[(ts->cursor + ts->lookahead) & NTOKENS_MASK].type;
+ } else {
+ tt = js_GetToken(cx, ts);
+ js_UngetToken(ts);
+ }
+ return tt;
+}
+
+JSTokenType
+js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts)
+{
+ JSTokenType tt;
+
+ JS_ASSERT(ts->lookahead == 0 ||
+ ON_CURRENT_LINE(ts, CURRENT_TOKEN(ts).pos));
+ ts->flags |= TSF_NEWLINES;
+ tt = js_PeekToken(cx, ts);
+ ts->flags &= ~TSF_NEWLINES;
+ return tt;
+}
+
+#define TBMIN 64
+
+static JSBool
+GrowTokenBuf(JSContext *cx, JSTokenBuf *tb)
+{
+ jschar *base;
+ ptrdiff_t offset, length;
+ size_t tbsize;
+ JSArenaPool *pool;
+
+ base = tb->base;
+ offset = PTRDIFF(tb->ptr, base, jschar);
+ pool = &cx->tempPool;
+ if (!base) {
+ tbsize = TBMIN * sizeof(jschar);
+ length = TBMIN;
+ JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize);
+ } else {
+ length = PTRDIFF(tb->limit, base, jschar);
+ tbsize = length * sizeof(jschar);
+ length <<= 1;
+ JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize);
+ }
+ if (!base) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ tb->base = base;
+ tb->limit = base + length;
+ tb->ptr = base + offset;
+ return JS_TRUE;
+}
+
+static JSBool
+AddToTokenBuf(JSContext *cx, JSTokenBuf *tb, jschar c)
+{
+ if (tb->ptr == tb->limit && !GrowTokenBuf(cx, tb))
+ return JS_FALSE;
+ *tb->ptr++ = c;
+ return JS_TRUE;
+}
+
+/*
+ * We have encountered a '\': check for a Unicode escape sequence after it,
+ * returning the character code value if we found a Unicode escape sequence.
+ * Otherwise, non-destructively return the original '\'.
+ */
+static int32
+GetUnicodeEscape(JSTokenStream *ts)
+{
+ jschar cp[5];
+ int32 c;
+
+ if (PeekChars(ts, 5, cp) && cp[0] == 'u' &&
+ JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]) &&
+ JS7_ISHEX(cp[3]) && JS7_ISHEX(cp[4]))
+ {
+ c = (((((JS7_UNHEX(cp[1]) << 4)
+ + JS7_UNHEX(cp[2])) << 4)
+ + JS7_UNHEX(cp[3])) << 4)
+ + JS7_UNHEX(cp[4]);
+ SkipChars(ts, 5);
+ return c;
+ }
+ return '\\';
+}
+
+JSTokenType
+js_GetToken(JSContext *cx, JSTokenStream *ts)
+{
+ JSTokenType tt;
+ JSToken *tp;
+ int32 c;
+ JSAtom *atom;
+ JSBool hadUnicodeEscape;
+
+#define INIT_TOKENBUF(tb) ((tb)->ptr = (tb)->base)
+#define FINISH_TOKENBUF(tb) if (!AddToTokenBuf(cx, tb, 0)) RETURN(TOK_ERROR)
+#define TOKEN_LENGTH(tb) ((tb)->ptr - (tb)->base - 1)
+#define RETURN(tt) { if (tt == TOK_ERROR) ts->flags |= TSF_ERROR; \
+ tp->pos.end.index = ts->linepos + \
+ (ts->linebuf.ptr - ts->linebuf.base) - \
+ ts->ungetpos; \
+ return (tp->type = tt); }
+
+ /* If there was a fatal error, keep returning TOK_ERROR. */
+ if (ts->flags & TSF_ERROR)
+ return TOK_ERROR;
+
+ /* Check for a pushed-back token resulting from mismatching lookahead. */
+ while (ts->lookahead != 0) {
+ ts->lookahead--;
+ ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
+ tt = CURRENT_TOKEN(ts).type;
+ if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES))
+ return tt;
+ }
+
+retry:
+ do {
+ c = GetChar(ts);
+ if (c == '\n') {
+ ts->flags &= ~TSF_DIRTYLINE;
+ if (ts->flags & TSF_NEWLINES)
+ break;
+ }
+ } while (JS_ISSPACE(c));
+
+ ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
+ tp = &CURRENT_TOKEN(ts);
+ tp->ptr = ts->linebuf.ptr - 1;
+ tp->pos.begin.index = ts->linepos + (tp->ptr - ts->linebuf.base);
+ tp->pos.begin.lineno = tp->pos.end.lineno = (uint16)ts->lineno;
+
+ if (c == EOF)
+ RETURN(TOK_EOF);
+ if (c != '-' && c != '\n')
+ ts->flags |= TSF_DIRTYLINE;
+
+ hadUnicodeEscape = JS_FALSE;
+ if (JS_ISIDENT_START(c) ||
+ (c == '\\' &&
+ (c = GetUnicodeEscape(ts),
+ hadUnicodeEscape = JS_ISIDENT_START(c)))) {
+ INIT_TOKENBUF(&ts->tokenbuf);
+ for (;;) {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ if (c == '\\') {
+ c = GetUnicodeEscape(ts);
+ if (!JS_ISIDENT(c))
+ break;
+ hadUnicodeEscape = JS_TRUE;
+ } else {
+ if (!JS_ISIDENT(c))
+ break;
+ }
+ }
+ UngetChar(ts, c);
+ FINISH_TOKENBUF(&ts->tokenbuf);
+
+ atom = js_AtomizeChars(cx,
+ ts->tokenbuf.base,
+ TOKEN_LENGTH(&ts->tokenbuf),
+ 0);
+ if (!atom)
+ RETURN(TOK_ERROR);
+ if (!hadUnicodeEscape && ATOM_KEYWORD(atom)) {
+ struct keyword *kw = ATOM_KEYWORD(atom);
+
+ if (JSVERSION_IS_ECMA(cx->version) || kw->version <= cx->version) {
+ tp->t_op = (JSOp) kw->op;
+ RETURN(kw->tokentype);
+ }
+ }
+ tp->t_op = JSOP_NAME;
+ tp->t_atom = atom;
+ RETURN(TOK_NAME);
+ }
+
+ if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(PeekChar(ts)))) {
+ jsint radix;
+ const jschar *endptr;
+ jsdouble dval;
+
+ radix = 10;
+ INIT_TOKENBUF(&ts->tokenbuf);
+
+ if (c == '0') {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ if (JS_TOLOWER(c) == 'x') {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ radix = 16;
+ } else if (JS7_ISDEC(c)) {
+ radix = 8;
+ }
+ }
+
+ while (JS7_ISHEX(c)) {
+ if (radix < 16) {
+ if (JS7_ISLET(c))
+ break;
+
+ /*
+ * We permit 08 and 09 as decimal numbers, which makes our
+ * behaviour a superset of the ECMA numeric grammar. We might
+ * not always be so permissive, so we warn about it.
+ */
+ if (radix == 8 && c >= '8') {
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING,
+ JSMSG_BAD_OCTAL,
+ c == '8' ? "08" : "09")) {
+ RETURN(TOK_ERROR);
+ }
+ radix = 10;
+ }
+ }
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ }
+
+ if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) {
+ if (c == '.') {
+ do {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ } while (JS7_ISDEC(c));
+ }
+ if (JS_TOLOWER(c) == 'e') {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ if (c == '+' || c == '-') {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ }
+ if (!JS7_ISDEC(c)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_MISSING_EXPONENT);
+ RETURN(TOK_ERROR);
+ }
+ do {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ } while (JS7_ISDEC(c));
+ }
+ }
+
+ UngetChar(ts, c);
+ FINISH_TOKENBUF(&ts->tokenbuf);
+
+ if (radix == 10) {
+ if (!js_strtod(cx, ts->tokenbuf.base, &endptr, &dval)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_OUT_OF_MEMORY);
+ RETURN(TOK_ERROR);
+ }
+ } else {
+ if (!js_strtointeger(cx, ts->tokenbuf.base, &endptr, radix, &dval)) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_OUT_OF_MEMORY);
+ RETURN(TOK_ERROR);
+ }
+ }
+ tp->t_dval = dval;
+ RETURN(TOK_NUMBER);
+ }
+
+ if (c == '"' || c == '\'') {
+ int32 val, qc = c;
+
+ INIT_TOKENBUF(&ts->tokenbuf);
+ while ((c = GetChar(ts)) != qc) {
+ if (c == '\n' || c == EOF) {
+ UngetChar(ts, c);
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_UNTERMINATED_STRING);
+ RETURN(TOK_ERROR);
+ }
+ if (c == '\\') {
+ switch (c = GetChar(ts)) {
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = '\v'; break;
+
+ default:
+ if ('0' <= c && c < '8') {
+ val = JS7_UNDEC(c);
+ c = PeekChar(ts);
+ if ('0' <= c && c < '8') {
+ val = 8 * val + JS7_UNDEC(c);
+ GetChar(ts);
+ c = PeekChar(ts);
+ if ('0' <= c && c < '8') {
+ int32 save = val;
+ val = 8 * val + JS7_UNDEC(c);
+ if (val <= 0377)
+ GetChar(ts);
+ else
+ val = save;
+ }
+ }
+ c = (jschar)val;
+ } else if (c == 'u') {
+ jschar cp[4];
+ if (PeekChars(ts, 4, cp) &&
+ JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) &&
+ JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) {
+ c = (((((JS7_UNHEX(cp[0]) << 4)
+ + JS7_UNHEX(cp[1])) << 4)
+ + JS7_UNHEX(cp[2])) << 4)
+ + JS7_UNHEX(cp[3]);
+ SkipChars(ts, 4);
+ }
+ } else if (c == 'x') {
+ jschar cp[2];
+ if (PeekChars(ts, 2, cp) &&
+ JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) {
+ c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
+ SkipChars(ts, 2);
+ }
+ } else if (c == '\n' && JSVERSION_IS_ECMA(cx->version)) {
+ /* ECMA follows C by removing escaped newlines. */
+ continue;
+ }
+ break;
+ }
+ }
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ }
+ FINISH_TOKENBUF(&ts->tokenbuf);
+ atom = js_AtomizeChars(cx,
+ ts->tokenbuf.base,
+ TOKEN_LENGTH(&ts->tokenbuf),
+ 0);
+ if (!atom)
+ RETURN(TOK_ERROR);
+ tp->pos.end.lineno = (uint16)ts->lineno;
+ tp->t_op = JSOP_STRING;
+ tp->t_atom = atom;
+ RETURN(TOK_STRING);
+ }
+
+ switch (c) {
+ case '\n':
+ c = TOK_EOL;
+ break;
+
+ case ';': c = TOK_SEMI; break;
+ case '.': c = TOK_DOT; break;
+ case '[': c = TOK_LB; break;
+ case ']': c = TOK_RB; break;
+ case '{': c = TOK_LC; break;
+ case '}': c = TOK_RC; break;
+ case '(': c = TOK_LP; break;
+ case ')': c = TOK_RP; break;
+ case ',': c = TOK_COMMA; break;
+ case '?': c = TOK_HOOK; break;
+
+ case ':':
+ /*
+ * Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an
+ * object initializer, likewise for setter.
+ */
+ tp->t_op = JSOP_NOP;
+ c = TOK_COLON;
+ break;
+
+ case '|':
+ if (MatchChar(ts, c)) {
+ c = TOK_OR;
+ } else if (MatchChar(ts, '=')) {
+ tp->t_op = JSOP_BITOR;
+ c = TOK_ASSIGN;
+ } else {
+ c = TOK_BITOR;
+ }
+ break;
+
+ case '^':
+ if (MatchChar(ts, '=')) {
+ tp->t_op = JSOP_BITXOR;
+ c = TOK_ASSIGN;
+ } else {
+ c = TOK_BITXOR;
+ }
+ break;
+
+ case '&':
+ if (MatchChar(ts, c)) {
+ c = TOK_AND;
+ } else if (MatchChar(ts, '=')) {
+ tp->t_op = JSOP_BITAND;
+ c = TOK_ASSIGN;
+ } else {
+ c = TOK_BITAND;
+ }
+ break;
+
+ case '=':
+ if (MatchChar(ts, c)) {
+#if JS_HAS_TRIPLE_EQOPS
+ tp->t_op = MatchChar(ts, c) ? JSOP_NEW_EQ : (JSOp)cx->jsop_eq;
+#else
+ tp->t_op = cx->jsop_eq;
+#endif
+ c = TOK_EQOP;
+ } else {
+ tp->t_op = JSOP_NOP;
+ c = TOK_ASSIGN;
+ }
+ break;
+
+ case '!':
+ if (MatchChar(ts, '=')) {
+#if JS_HAS_TRIPLE_EQOPS
+ tp->t_op = MatchChar(ts, '=') ? JSOP_NEW_NE : (JSOp)cx->jsop_ne;
+#else
+ tp->t_op = cx->jsop_ne;
+#endif
+ c = TOK_EQOP;
+ } else {
+ tp->t_op = JSOP_NOT;
+ c = TOK_UNARYOP;
+ }
+ break;
+
+ case '<':
+ /* NB: treat HTML begin-comment as comment-till-end-of-line */
+ if (MatchChar(ts, '!')) {
+ if (MatchChar(ts, '-')) {
+ if (MatchChar(ts, '-'))
+ goto skipline;
+ UngetChar(ts, '-');
+ }
+ UngetChar(ts, '!');
+ }
+ if (MatchChar(ts, c)) {
+ tp->t_op = JSOP_LSH;
+ c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;
+ } else {
+ tp->t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT;
+ c = TOK_RELOP;
+ }
+ break;
+
+ case '>':
+ if (MatchChar(ts, c)) {
+ tp->t_op = MatchChar(ts, c) ? JSOP_URSH : JSOP_RSH;
+ c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;
+ } else {
+ tp->t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT;
+ c = TOK_RELOP;
+ }
+ break;
+
+ case '*':
+ tp->t_op = JSOP_MUL;
+ c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_STAR;
+ break;
+
+ case '/':
+ if (MatchChar(ts, '/')) {
+skipline:
+ while ((c = GetChar(ts)) != EOF && c != '\n')
+ /* skip to end of line */;
+ UngetChar(ts, c);
+ goto retry;
+ }
+ if (MatchChar(ts, '*')) {
+ while ((c = GetChar(ts)) != EOF &&
+ !(c == '*' && MatchChar(ts, '/'))) {
+ /* Ignore all characters until comment close. */
+ }
+ if (c == EOF) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_UNTERMINATED_COMMENT);
+ RETURN(TOK_ERROR);
+ }
+ goto retry;
+ }
+
+#if JS_HAS_REGEXPS
+ if (ts->flags & TSF_REGEXP) {
+ JSObject *obj;
+ uintN flags;
+
+ INIT_TOKENBUF(&ts->tokenbuf);
+ while ((c = GetChar(ts)) != '/') {
+ if (c == '\n' || c == EOF) {
+ UngetChar(ts, c);
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_UNTERMINATED_REGEXP);
+ RETURN(TOK_ERROR);
+ }
+ if (c == '\\') {
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ c = GetChar(ts);
+ }
+ if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))
+ RETURN(TOK_ERROR);
+ }
+ FINISH_TOKENBUF(&ts->tokenbuf);
+ for (flags = 0; ; ) {
+ if (MatchChar(ts, 'g'))
+ flags |= JSREG_GLOB;
+ else if (MatchChar(ts, 'i'))
+ flags |= JSREG_FOLD;
+ else if (MatchChar(ts, 'm'))
+ flags |= JSREG_MULTILINE;
+ else
+ break;
+ }
+ c = PeekChar(ts);
+ if (JS7_ISLET(c)) {
+ tp->ptr = ts->linebuf.ptr - 1;
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_BAD_REGEXP_FLAG);
+ (void) GetChar(ts);
+ RETURN(TOK_ERROR);
+ }
+ obj = js_NewRegExpObject(cx, ts,
+ ts->tokenbuf.base,
+ TOKEN_LENGTH(&ts->tokenbuf),
+ flags);
+ if (!obj)
+ RETURN(TOK_ERROR);
+ atom = js_AtomizeObject(cx, obj, 0);
+ if (!atom)
+ RETURN(TOK_ERROR);
+ tp->t_op = JSOP_OBJECT;
+ tp->t_atom = atom;
+ RETURN(TOK_OBJECT);
+ }
+#endif /* JS_HAS_REGEXPS */
+
+ tp->t_op = JSOP_DIV;
+ c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
+ break;
+
+ case '%':
+ tp->t_op = JSOP_MOD;
+ c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
+ break;
+
+ case '~':
+ tp->t_op = JSOP_BITNOT;
+ c = TOK_UNARYOP;
+ break;
+
+ case '+':
+ if (MatchChar(ts, '=')) {
+ tp->t_op = JSOP_ADD;
+ c = TOK_ASSIGN;
+ } else if (MatchChar(ts, c)) {
+ c = TOK_INC;
+ } else {
+ tp->t_op = JSOP_POS;
+ c = TOK_PLUS;
+ }
+ break;
+
+ case '-':
+ if (MatchChar(ts, '=')) {
+ tp->t_op = JSOP_SUB;
+ c = TOK_ASSIGN;
+ } else if (MatchChar(ts, c)) {
+ if (PeekChar(ts) == '>' && !(ts->flags & TSF_DIRTYLINE))
+ goto skipline;
+ c = TOK_DEC;
+ } else {
+ tp->t_op = JSOP_NEG;
+ c = TOK_MINUS;
+ }
+ ts->flags |= TSF_DIRTYLINE;
+ break;
+
+#if JS_HAS_SHARP_VARS
+ case '#':
+ {
+ uint32 n;
+
+ c = GetChar(ts);
+ if (!JS7_ISDEC(c)) {
+ UngetChar(ts, c);
+ goto badchar;
+ }
+ n = (uint32)JS7_UNDEC(c);
+ for (;;) {
+ c = GetChar(ts);
+ if (!JS7_ISDEC(c))
+ break;
+ n = 10 * n + JS7_UNDEC(c);
+ if (n >= ATOM_INDEX_LIMIT) {
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_SHARPVAR_TOO_BIG);
+ RETURN(TOK_ERROR);
+ }
+ }
+ tp->t_dval = (jsdouble) n;
+ if (JS_HAS_STRICT_OPTION(cx) &&
+ (c == '=' || c == '#')) {
+ char buf[20];
+ JS_snprintf(buf, sizeof buf, "#%u%c", n, c);
+ if (!js_ReportCompileErrorNumber(cx, ts, NULL,
+ JSREPORT_WARNING |
+ JSREPORT_STRICT,
+ JSMSG_DEPRECATED_USAGE,
+ buf)) {
+ RETURN(TOK_ERROR);
+ }
+ }
+ if (c == '=')
+ RETURN(TOK_DEFSHARP);
+ if (c == '#')
+ RETURN(TOK_USESHARP);
+ goto badchar;
+ }
+
+ badchar:
+#endif /* JS_HAS_SHARP_VARS */
+
+ default:
+ js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+ JSMSG_ILLEGAL_CHARACTER);
+ RETURN(TOK_ERROR);
+ }
+
+ JS_ASSERT(c < TOK_LIMIT);
+ RETURN((JSTokenType)c);
+
+#undef INIT_TOKENBUF
+#undef FINISH_TOKENBUF
+#undef TOKEN_LENGTH
+#undef RETURN
+}
+
+void
+js_UngetToken(JSTokenStream *ts)
+{
+ JS_ASSERT(ts->lookahead < NTOKENS_MASK);
+ if (ts->flags & TSF_ERROR)
+ return;
+ ts->lookahead++;
+ ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
+}
+
+JSBool
+js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
+{
+ if (js_GetToken(cx, ts) == tt)
+ return JS_TRUE;
+ js_UngetToken(ts);
+ return JS_FALSE;
+}
diff --git a/src/dom/js/jsscan.h b/src/dom/js/jsscan.h
new file mode 100644
index 000000000..c61eff926
--- /dev/null
+++ b/src/dom/js/jsscan.h
@@ -0,0 +1,264 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsscan_h___
+#define jsscan_h___
+/*
+ * JS lexical scanner interface.
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include "jsopcode.h"
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+JS_BEGIN_EXTERN_C
+
+typedef enum JSTokenType {
+ TOK_ERROR = -1, /* well-known as the only code < EOF */
+ TOK_EOF = 0, /* end of file */
+ TOK_EOL = 1, /* end of line */
+ TOK_SEMI = 2, /* semicolon */
+ TOK_COMMA = 3, /* comma operator */
+ TOK_ASSIGN = 4, /* assignment ops (= += -= etc.) */
+ TOK_HOOK = 5, TOK_COLON = 6, /* conditional (?:) */
+ TOK_OR = 7, /* logical or (||) */
+ TOK_AND = 8, /* logical and (&&) */
+ TOK_BITOR = 9, /* bitwise-or (|) */
+ TOK_BITXOR = 10, /* bitwise-xor (^) */
+ TOK_BITAND = 11, /* bitwise-and (&) */
+ TOK_EQOP = 12, /* equality ops (== !=) */
+ TOK_RELOP = 13, /* relational ops (< <= > >=) */
+ TOK_SHOP = 14, /* shift ops (<< >> >>>) */
+ TOK_PLUS = 15, /* plus */
+ TOK_MINUS = 16, /* minus */
+ TOK_STAR = 17, TOK_DIVOP = 18, /* multiply/divide ops (* / %) */
+ TOK_UNARYOP = 19, /* unary prefix operator */
+ TOK_INC = 20, TOK_DEC = 21, /* increment/decrement (++ --) */
+ TOK_DOT = 22, /* member operator (.) */
+ TOK_LB = 23, TOK_RB = 24, /* left and right brackets */
+ TOK_LC = 25, TOK_RC = 26, /* left and right curlies (braces) */
+ TOK_LP = 27, TOK_RP = 28, /* left and right parentheses */
+ TOK_NAME = 29, /* identifier */
+ TOK_NUMBER = 30, /* numeric constant */
+ TOK_STRING = 31, /* string constant */
+ TOK_OBJECT = 32, /* RegExp or other object constant */
+ TOK_PRIMARY = 33, /* true, false, null, this, super */
+ TOK_FUNCTION = 34, /* function keyword */
+ TOK_EXPORT = 35, /* export keyword */
+ TOK_IMPORT = 36, /* import keyword */
+ TOK_IF = 37, /* if keyword */
+ TOK_ELSE = 38, /* else keyword */
+ TOK_SWITCH = 39, /* switch keyword */
+ TOK_CASE = 40, /* case keyword */
+ TOK_DEFAULT = 41, /* default keyword */
+ TOK_WHILE = 42, /* while keyword */
+ TOK_DO = 43, /* do keyword */
+ TOK_FOR = 44, /* for keyword */
+ TOK_BREAK = 45, /* break keyword */
+ TOK_CONTINUE = 46, /* continue keyword */
+ TOK_IN = 47, /* in keyword */
+ TOK_VAR = 48, /* var keyword */
+ TOK_WITH = 49, /* with keyword */
+ TOK_RETURN = 50, /* return keyword */
+ TOK_NEW = 51, /* new keyword */
+ TOK_DELETE = 52, /* delete keyword */
+ TOK_DEFSHARP = 53, /* #n= for object/array initializers */
+ TOK_USESHARP = 54, /* #n# for object/array initializers */
+ TOK_TRY = 55, /* try keyword */
+ TOK_CATCH = 56, /* catch keyword */
+ TOK_FINALLY = 57, /* finally keyword */
+ TOK_THROW = 58, /* throw keyword */
+ TOK_INSTANCEOF = 59, /* instanceof keyword */
+ TOK_DEBUGGER = 60, /* debugger keyword */
+ TOK_RESERVED, /* reserved keywords */
+ TOK_LIMIT /* domain size */
+} JSTokenType;
+
+#define IS_PRIMARY_TOKEN(tt) \
+ ((uintN)((tt) - TOK_NAME) <= (uintN)(TOK_PRIMARY - TOK_NAME))
+
+struct JSTokenPtr {
+ uint16 index; /* index of char in physical line */
+ uint16 lineno; /* physical line number */
+};
+
+struct JSTokenPos {
+ JSTokenPtr begin; /* first character and line of token */
+ JSTokenPtr end; /* index 1 past last char, last line */
+};
+
+struct JSToken {
+ JSTokenType type; /* char value or above enumerator */
+ JSTokenPos pos; /* token position in file */
+ jschar *ptr; /* beginning of token in line buffer */
+ union {
+ struct {
+ JSOp op; /* operator, for minimal parser */
+ JSAtom *atom; /* atom table entry */
+ } s;
+ jsdouble dval; /* floating point number */
+ } u;
+};
+
+#define t_op u.s.op
+#define t_atom u.s.atom
+#define t_dval u.dval
+
+typedef struct JSTokenBuf {
+ jschar *base; /* base of line or stream buffer */
+ jschar *limit; /* limit for quick bounds check */
+ jschar *ptr; /* next char to get, or slot to use */
+} JSTokenBuf;
+
+#define JS_LINE_LIMIT 256 /* logical line buffer size limit --
+ physical line length is unlimited */
+#define NTOKENS 4 /* 1 current + 2 lookahead, rounded */
+#define NTOKENS_MASK (NTOKENS-1) /* to power of 2 to avoid divmod by 3 */
+
+struct JSTokenStream {
+ JSToken tokens[NTOKENS];/* circular token buffer */
+ uintN cursor; /* index of last parsed token */
+ uintN lookahead; /* count of lookahead tokens */
+ uintN lineno; /* current line number */
+ uintN ungetpos; /* next free char slot in ungetbuf */
+ jschar ungetbuf[6]; /* at most 6, for \uXXXX lookahead */
+ uintN flags; /* flags -- see below */
+ ptrdiff_t linelen; /* physical linebuf segment length */
+ ptrdiff_t linepos; /* linebuf offset in physical line */
+ JSTokenBuf linebuf; /* line buffer for diagnostics */
+ JSTokenBuf userbuf; /* user input buffer if !file */
+ JSTokenBuf tokenbuf; /* current token string buffer */
+ const char *filename; /* input filename or null */
+ FILE *file; /* stdio stream if reading from file */
+ JSPrincipals *principals; /* principals associated with source */
+ JSSourceHandler listener; /* callback for source; eg debugger */
+ void *listenerData; /* listener 'this' data */
+ void *listenerTSData;/* listener data for this TokenStream */
+};
+
+#define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor])
+#define ON_CURRENT_LINE(ts,pos) ((uint16)(ts)->lineno == (pos).end.lineno)
+
+/* JSTokenStream flags */
+#define TSF_ERROR 0x01 /* fatal error while compiling */
+#define TSF_EOF 0x02 /* hit end of file */
+#define TSF_NEWLINES 0x04 /* tokenize newlines */
+#define TSF_REGEXP 0x08 /* looking for a regular expression */
+#define TSF_NLFLAG 0x20 /* last linebuf ended with \n */
+#define TSF_CRFLAG 0x40 /* linebuf would have ended with \r */
+#define TSF_DIRTYLINE 0x80 /* stuff other than whitespace since start of line */
+
+/* Unicode separators that are treated as line terminators, in addition to \n, \r */
+#define LINE_SEPARATOR 0x2028
+#define PARA_SEPARATOR 0x2029
+
+/*
+ * Create a new token stream, either from an input buffer or from a file.
+ * Return null on file-open or memory-allocation failure.
+ *
+ * NB: All of js_New{,Buffer,File}TokenStream() return a pointer to transient
+ * memory in the current context's temp pool. This memory is deallocated via
+ * JS_ARENA_RELEASE() after parsing is finished.
+ */
+extern JSTokenStream *
+js_NewTokenStream(JSContext *cx, const jschar *base, size_t length,
+ const char *filename, uintN lineno, JSPrincipals *principals);
+
+extern JS_FRIEND_API(JSTokenStream *)
+js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length);
+
+extern JS_FRIEND_API(JSTokenStream *)
+js_NewFileTokenStream(JSContext *cx, const char *filename, FILE *defaultfp);
+
+extern JS_FRIEND_API(JSBool)
+js_CloseTokenStream(JSContext *cx, JSTokenStream *ts);
+
+/*
+ * Initialize the scanner, installing JS keywords into cx's global scope.
+ */
+extern JSBool
+js_InitScanner(JSContext *cx);
+
+/*
+ * Friend-exported API entry point to call a mapping function on each reserved
+ * identifier in the scanner's keyword table.
+ */
+extern JS_FRIEND_API(void)
+js_MapKeywords(void (*mapfun)(const char *));
+
+/*
+ * Report a compile-time error by its number, using ts or cg to show context.
+ * Return true for a warning, false for an error.
+ */
+extern JSBool
+js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts,
+ JSCodeGenerator *cg, uintN flags,
+ const uintN errorNumber, ...);
+
+/*
+ * Look ahead one token and return its type.
+ */
+extern JSTokenType
+js_PeekToken(JSContext *cx, JSTokenStream *ts);
+
+extern JSTokenType
+js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts);
+
+/*
+ * Get the next token from ts.
+ */
+extern JSTokenType
+js_GetToken(JSContext *cx, JSTokenStream *ts);
+
+/*
+ * Push back the last scanned token onto ts.
+ */
+extern void
+js_UngetToken(JSTokenStream *ts);
+
+/*
+ * Get the next token from ts if its type is tt.
+ */
+extern JSBool
+js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt);
+
+JS_END_EXTERN_C
+
+#endif /* jsscan_h___ */
diff --git a/src/dom/js/jsscope.c b/src/dom/js/jsscope.c
new file mode 100644
index 000000000..20243e9b7
--- /dev/null
+++ b/src/dom/js/jsscope.c
@@ -0,0 +1,1581 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS symbol tables.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsarena.h"
+#include "jsbit.h"
+#include "jsclist.h"
+#include "jsdhash.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsdbgapi.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsscope.h"
+#include "jsstr.h"
+
+JSScope *
+js_GetMutableScope(JSContext *cx, JSObject *obj)
+{
+ JSScope *scope, *newscope;
+
+ scope = OBJ_SCOPE(obj);
+ JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
+ if (scope->object == obj)
+ return scope;
+ newscope = js_NewScope(cx, 0, scope->map.ops, LOCKED_OBJ_GET_CLASS(obj),
+ obj);
+ if (!newscope)
+ return NULL;
+ JS_LOCK_SCOPE(cx, newscope);
+ obj->map = js_HoldObjectMap(cx, &newscope->map);
+ scope = (JSScope *) js_DropObjectMap(cx, &scope->map, obj);
+ JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope);
+ return newscope;
+}
+
+/*
+ * JSScope uses multiplicative hashing, _a la_ jsdhash.[ch], but specialized
+ * to minimize footprint. But if a scope has fewer than SCOPE_HASH_THRESHOLD
+ * entries, we use linear search and avoid allocating scope->table.
+ */
+#define SCOPE_HASH_THRESHOLD 6
+#define MIN_SCOPE_SIZE_LOG2 4
+#define MIN_SCOPE_SIZE JS_BIT(MIN_SCOPE_SIZE_LOG2)
+#define SCOPE_TABLE_NBYTES(n) ((n) * sizeof(JSScopeProperty *))
+
+static void
+InitMinimalScope(JSScope *scope)
+{
+ scope->hashShift = JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2;
+ scope->entryCount = scope->removedCount = 0;
+ scope->table = NULL;
+ scope->lastProp = NULL;
+}
+
+static JSBool
+CreateScopeTable(JSScope *scope)
+{
+ int sizeLog2;
+ JSScopeProperty *sprop, **spp;
+
+ JS_ASSERT(!scope->table);
+ JS_ASSERT(scope->lastProp);
+
+ if (scope->entryCount > SCOPE_HASH_THRESHOLD) {
+ /*
+ * Ouch: calloc failed at least once already -- let's try again,
+ * overallocating to hold at least twice the current population.
+ */
+ sizeLog2 = JS_CeilingLog2(2 * scope->entryCount);
+ scope->hashShift = JS_DHASH_BITS - sizeLog2;
+ } else {
+ JS_ASSERT(scope->hashShift == JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2);
+ sizeLog2 = MIN_SCOPE_SIZE_LOG2;
+ }
+
+ scope->table = (JSScopeProperty **)
+ calloc(JS_BIT(sizeLog2), sizeof(JSScopeProperty *));
+ if (!scope->table)
+ return JS_FALSE;
+
+ scope->hashShift = JS_DHASH_BITS - sizeLog2;
+ for (sprop = scope->lastProp; sprop; sprop = sprop->parent) {
+ spp = js_SearchScope(scope, sprop->id, JS_TRUE);
+ SPROP_STORE_PRESERVING_COLLISION(spp, sprop);
+ }
+ return JS_TRUE;
+}
+
+JSScope *
+js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
+ JSObject *obj)
+{
+ JSScope *scope;
+
+ scope = (JSScope *) JS_malloc(cx, sizeof(JSScope));
+ if (!scope)
+ return NULL;
+
+ js_InitObjectMap(&scope->map, nrefs, ops, clasp);
+ scope->object = obj;
+ scope->flags = 0;
+ InitMinimalScope(scope);
+
+#ifdef JS_THREADSAFE
+ scope->ownercx = cx;
+ memset(&scope->lock, 0, sizeof scope->lock);
+
+ /*
+ * Set u.link = NULL, not u.count = 0, in case the target architecture's
+ * null pointer has a non-zero integer representation.
+ */
+ scope->u.link = NULL;
+
+#ifdef DEBUG
+ scope->file[0] = scope->file[1] = scope->file[2] = scope->file[3] = NULL;
+ scope->line[0] = scope->line[1] = scope->line[2] = scope->line[3] = 0;
+#endif
+#endif
+
+ JS_RUNTIME_METER(cx->runtime, liveScopes);
+ JS_RUNTIME_METER(cx->runtime, totalScopes);
+ return scope;
+}
+
+#ifdef DEBUG_SCOPE_COUNT
+extern void
+js_unlog_scope(JSScope *scope);
+#endif
+
+void
+js_DestroyScope(JSContext *cx, JSScope *scope)
+{
+#ifdef DEBUG_SCOPE_COUNT
+ js_unlog_scope(scope);
+#endif
+
+#ifdef JS_THREADSAFE
+ /* Scope must be single-threaded at this point, so set scope->ownercx. */
+ JS_ASSERT(scope->u.count == 0);
+ scope->ownercx = cx;
+ js_FinishLock(&scope->lock);
+#endif
+ if (scope->table)
+ JS_free(cx, scope->table);
+
+#ifdef DEBUG
+ JS_LOCK_RUNTIME_VOID(cx->runtime,
+ cx->runtime->liveScopeProps -= scope->entryCount);
+#endif
+ JS_RUNTIME_UNMETER(cx->runtime, liveScopes);
+ JS_free(cx, scope);
+}
+
+#ifdef DEBUG_brendan
+typedef struct JSScopeStats {
+ jsrefcount searches;
+ jsrefcount steps;
+ jsrefcount hits;
+ jsrefcount misses;
+ jsrefcount stepHits;
+ jsrefcount stepMisses;
+ jsrefcount adds;
+ jsrefcount redundantAdds;
+ jsrefcount addFailures;
+ jsrefcount changeFailures;
+ jsrefcount compresses;
+ jsrefcount grows;
+ jsrefcount removes;
+ jsrefcount removeFrees;
+ jsrefcount uselessRemoves;
+ jsrefcount shrinks;
+} JSScopeStats;
+
+JS_FRIEND_DATA(JSScopeStats) js_scope_stats;
+
+# define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x)
+#else
+# define METER(x) /* nothing */
+#endif
+
+/*
+ * Double hashing needs the second hash code to be relatively prime to table
+ * size, so we simply make hash2 odd. The inputs to multiplicative hash are
+ * the golden ratio, expressed as a fixed-point 32 bit fraction, and the int
+ * property index or named property's atom number (observe that most objects
+ * have either no indexed properties, or almost all indexed and a few names,
+ * so collisions between index and atom number are unlikely).
+ */
+#define SCOPE_HASH0(id) (HASH_ID(id) * JS_GOLDEN_RATIO)
+#define SCOPE_HASH1(hash0,shift) ((hash0) >> (shift))
+#define SCOPE_HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1)
+
+JS_FRIEND_API(JSScopeProperty **)
+js_SearchScope(JSScope *scope, jsid id, JSBool adding)
+{
+ JSHashNumber hash0, hash1, hash2;
+ int hashShift, sizeLog2;
+ JSScopeProperty *stored, *sprop, **spp, **firstRemoved;
+ uint32 sizeMask;
+
+ METER(searches);
+ if (!scope->table) {
+ /* Not enough properties to justify hashing: search from lastProp. */
+ JS_ASSERT(!SCOPE_HAD_MIDDLE_DELETE(scope));
+ for (spp = &scope->lastProp; (sprop = *spp); spp = &sprop->parent) {
+ if (sprop->id == id) {
+ METER(hits);
+ return spp;
+ }
+ }
+ METER(misses);
+ return spp;
+ }
+
+ /* Compute the primary hash address. */
+ hash0 = SCOPE_HASH0(id);
+ hashShift = scope->hashShift;
+ hash1 = SCOPE_HASH1(hash0, hashShift);
+ spp = scope->table + hash1;
+
+ /* Miss: return space for a new entry. */
+ stored = *spp;
+ if (SPROP_IS_FREE(stored)) {
+ METER(misses);
+ return spp;
+ }
+
+ /* Hit: return entry. */
+ sprop = SPROP_CLEAR_COLLISION(stored);
+ if (sprop && sprop->id == id) {
+ METER(hits);
+ return spp;
+ }
+
+ /* Collision: double hash. */
+ sizeLog2 = JS_DHASH_BITS - hashShift;
+ hash2 = SCOPE_HASH2(hash0, sizeLog2, hashShift);
+ sizeMask = JS_BITMASK(sizeLog2);
+
+ /* Save the first removed entry pointer so we can recycle it if adding. */
+ if (SPROP_IS_REMOVED(stored)) {
+ firstRemoved = spp;
+ } else {
+ firstRemoved = NULL;
+ if (adding && !SPROP_HAD_COLLISION(stored))
+ SPROP_FLAG_COLLISION(spp, sprop);
+ }
+
+ for (;;) {
+ METER(steps);
+ hash1 -= hash2;
+ hash1 &= sizeMask;
+ spp = scope->table + hash1;
+
+ stored = *spp;
+ if (SPROP_IS_FREE(stored)) {
+ METER(stepMisses);
+ return (adding && firstRemoved) ? firstRemoved : spp;
+ }
+
+ sprop = SPROP_CLEAR_COLLISION(stored);
+ if (sprop && sprop->id == id) {
+ METER(stepHits);
+ return spp;
+ }
+
+ if (SPROP_IS_REMOVED(stored)) {
+ if (!firstRemoved)
+ firstRemoved = spp;
+ } else {
+ if (adding && !SPROP_HAD_COLLISION(stored))
+ SPROP_FLAG_COLLISION(spp, sprop);
+ }
+ }
+
+ /* NOTREACHED */
+ return NULL;
+}
+
+static JSBool
+ChangeScope(JSContext *cx, JSScope *scope, int change)
+{
+ int oldlog2, newlog2;
+ uint32 oldsize, newsize, nbytes;
+ JSScopeProperty **table, **oldtable, **spp, **oldspp, *sprop;
+
+ /* Grow, shrink, or compress by changing scope->table. */
+ oldlog2 = JS_DHASH_BITS - scope->hashShift;
+ newlog2 = oldlog2 + change;
+ oldsize = JS_BIT(oldlog2);
+ newsize = JS_BIT(newlog2);
+ nbytes = SCOPE_TABLE_NBYTES(newsize);
+ table = (JSScopeProperty **) calloc(nbytes, 1);
+ if (!table) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+
+ /* Now that we have a new table allocated, update scope members. */
+ scope->hashShift = JS_DHASH_BITS - newlog2;
+ scope->removedCount = 0;
+ oldtable = scope->table;
+ scope->table = table;
+
+ /* Copy only live entries, leaving removed and free ones behind. */
+ for (oldspp = oldtable; oldsize != 0; oldspp++) {
+ sprop = SPROP_FETCH(oldspp);
+ if (sprop) {
+ spp = js_SearchScope(scope, sprop->id, JS_TRUE);
+ JS_ASSERT(SPROP_IS_FREE(*spp));
+ *spp = sprop;
+ }
+ oldsize--;
+ }
+
+ /* Finally, free the old table storage. */
+ JS_free(cx, oldtable);
+ return JS_TRUE;
+}
+
+/*
+ * Take care to exclude the mark and duplicate bits, in case we're called from
+ * the GC, or we are searching for a property that has not yet been flagged as
+ * a duplicate when making a duplicate formal parameter.
+ */
+#define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_IS_DUPLICATE)
+
+JS_STATIC_DLL_CALLBACK(JSDHashNumber)
+js_HashScopeProperty(JSDHashTable *table, const void *key)
+{
+ const JSScopeProperty *sprop = (const JSScopeProperty *)key;
+ JSDHashNumber hash;
+ JSPropertyOp gsop;
+
+ /* Accumulate from least to most random so the low bits are most random. */
+ hash = 0;
+ gsop = sprop->getter;
+ if (gsop)
+ hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ (jsword)gsop;
+ gsop = sprop->setter;
+ if (gsop)
+ hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ (jsword)gsop;
+
+ hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4)
+ ^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED);
+
+ hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->attrs;
+ hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->shortid;
+ hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->slot;
+ hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->id;
+ return hash;
+}
+
+#define SPROP_MATCH(sprop, child) \
+ SPROP_MATCH_PARAMS(sprop, (child)->id, (child)->getter, (child)->setter, \
+ (child)->slot, (child)->attrs, (child)->flags, \
+ (child)->shortid)
+
+#define SPROP_MATCH_PARAMS(sprop, aid, agetter, asetter, aslot, aattrs, \
+ aflags, ashortid) \
+ ((sprop)->id == (aid) && \
+ SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \
+ aflags, ashortid))
+
+#define SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \
+ aflags, ashortid) \
+ ((sprop)->getter == (agetter) && \
+ (sprop)->setter == (asetter) && \
+ (sprop)->slot == (aslot) && \
+ (sprop)->attrs == (aattrs) && \
+ (((sprop)->flags ^ (aflags)) & ~SPROP_FLAGS_NOT_MATCHED) == 0 && \
+ (sprop)->shortid == (ashortid))
+
+JS_STATIC_DLL_CALLBACK(JSBool)
+js_MatchScopeProperty(JSDHashTable *table,
+ const JSDHashEntryHdr *hdr,
+ const void *key)
+{
+ const JSPropertyTreeEntry *entry = (const JSPropertyTreeEntry *)hdr;
+ const JSScopeProperty *sprop = entry->child;
+ const JSScopeProperty *kprop = (const JSScopeProperty *)key;
+
+ return SPROP_MATCH(sprop, kprop);
+}
+
+static const JSDHashTableOps PropertyTreeHashOps = {
+ JS_DHashAllocTable,
+ JS_DHashFreeTable,
+ JS_DHashGetKeyStub,
+ js_HashScopeProperty,
+ js_MatchScopeProperty,
+ JS_DHashMoveEntryStub,
+ JS_DHashClearEntryStub,
+ JS_DHashFinalizeStub,
+ NULL
+};
+
+/*
+ * A property tree node on rt->propertyFreeList overlays the following prefix
+ * struct on JSScopeProperty.
+ */
+typedef struct FreeNode {
+ jsid id;
+ JSScopeProperty *next;
+ JSScopeProperty **prevp;
+} FreeNode;
+
+#define FREENODE(sprop) ((FreeNode *) (sprop))
+
+#define FREENODE_INSERT(list, sprop) \
+ JS_BEGIN_MACRO \
+ FREENODE(sprop)->next = (list); \
+ FREENODE(sprop)->prevp = &(list); \
+ if (list) \
+ FREENODE(list)->prevp = &FREENODE(sprop)->next; \
+ (list) = (sprop); \
+ JS_END_MACRO
+
+#define FREENODE_REMOVE(sprop) \
+ JS_BEGIN_MACRO \
+ *FREENODE(sprop)->prevp = FREENODE(sprop)->next; \
+ if (FREENODE(sprop)->next) \
+ FREENODE(FREENODE(sprop)->next)->prevp = FREENODE(sprop)->prevp; \
+ JS_END_MACRO
+
+/* NB: Called with the runtime lock held. */
+static JSScopeProperty *
+NewScopeProperty(JSRuntime *rt)
+{
+ JSScopeProperty *sprop;
+
+ sprop = rt->propertyFreeList;
+ if (sprop) {
+ FREENODE_REMOVE(sprop);
+ } else {
+ JS_ARENA_ALLOCATE_CAST(sprop, JSScopeProperty *,
+ &rt->propertyArenaPool,
+ sizeof(JSScopeProperty));
+ if (!sprop)
+ return NULL;
+ }
+
+ JS_RUNTIME_METER(rt, livePropTreeNodes);
+ JS_RUNTIME_METER(rt, totalPropTreeNodes);
+ return sprop;
+}
+
+#define CHUNKY_KIDS_TAG ((jsuword)1)
+#define KIDS_IS_CHUNKY(kids) ((jsuword)(kids) & CHUNKY_KIDS_TAG)
+#define KIDS_TO_CHUNK(kids) ((PropTreeKidsChunk *) \
+ ((jsuword)(kids) & ~CHUNKY_KIDS_TAG))
+#define CHUNK_TO_KIDS(chunk) ((JSScopeProperty *) \
+ ((jsuword)(chunk) | CHUNKY_KIDS_TAG))
+#define MAX_KIDS_PER_CHUNK 10
+
+typedef struct PropTreeKidsChunk PropTreeKidsChunk;
+
+struct PropTreeKidsChunk {
+ JSScopeProperty *kids[MAX_KIDS_PER_CHUNK];
+ PropTreeKidsChunk *next;
+};
+
+static PropTreeKidsChunk *
+NewPropTreeKidsChunk(JSRuntime *rt)
+{
+ PropTreeKidsChunk *chunk;
+
+ chunk = calloc(1, sizeof *chunk);
+ if (!chunk)
+ return NULL;
+ JS_ASSERT(((jsuword)chunk & CHUNKY_KIDS_TAG) == 0);
+ JS_RUNTIME_METER(rt, propTreeKidsChunks);
+ return chunk;
+}
+
+static void
+DestroyPropTreeKidsChunk(JSRuntime *rt, PropTreeKidsChunk *chunk)
+{
+ JS_RUNTIME_UNMETER(rt, propTreeKidsChunks);
+ free(chunk);
+}
+
+/* NB: Called with the runtime lock held. */
+static JSBool
+InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent,
+ JSScopeProperty *child)
+{
+ JSPropertyTreeEntry *entry;
+ JSScopeProperty **childp, *kids, *sprop;
+ PropTreeKidsChunk *chunk, **chunkp;
+ uintN i;
+
+ JS_ASSERT(!parent || child->parent != parent);
+
+ if (!parent) {
+ entry = (JSPropertyTreeEntry *)
+ JS_DHashTableOperate(&rt->propertyTreeHash, child, JS_DHASH_ADD);
+ if (!entry)
+ return JS_FALSE;
+ childp = &entry->child;
+ sprop = *childp;
+ if (!sprop) {
+ *childp = child;
+ } else {
+ /*
+ * A "Duplicate child" case.
+ *
+ * We can't do away with child, as at least one live scope entry
+ * still points at it. What's more, that scope's lastProp chains
+ * through an ancestor line to reach child, and js_Enumerate and
+ * others count on this linkage. We must leave child out of the
+ * hash table, and not require it to be there when we eventually
+ * GC it (see RemovePropertyTreeChild, below).
+ *
+ * It is necessary to leave the duplicate child out of the hash
+ * table to preserve entry uniqueness. It is safe to leave the
+ * child out of the hash table (unlike the duplicate child cases
+ * below), because the child's parent link will be null, which
+ * can't dangle.
+ */
+ JS_ASSERT(sprop != child && SPROP_MATCH(sprop, child));
+ JS_RUNTIME_METER(rt, duplicatePropTreeNodes);
+ }
+ } else {
+ childp = &parent->kids;
+ kids = *childp;
+ if (kids) {
+ if (KIDS_IS_CHUNKY(kids)) {
+ chunk = KIDS_TO_CHUNK(kids);
+ do {
+ for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
+ childp = &chunk->kids[i];
+ sprop = *childp;
+ if (!sprop)
+ goto insert;
+
+ JS_ASSERT(sprop != child);
+ if (SPROP_MATCH(sprop, child)) {
+ /*
+ * Duplicate child, see comment above. In this
+ * case, we must let the duplicate be inserted at
+ * this level in the tree, so we keep iterating,
+ * looking for an empty slot in which to insert.
+ */
+ JS_ASSERT(sprop != child);
+ JS_RUNTIME_METER(rt, duplicatePropTreeNodes);
+ }
+ }
+ chunkp = &chunk->next;
+ } while ((chunk = *chunkp) != NULL);
+
+ chunk = NewPropTreeKidsChunk(rt);
+ if (!chunk)
+ return JS_FALSE;
+ *chunkp = chunk;
+ childp = &chunk->kids[0];
+ } else {
+ sprop = kids;
+ JS_ASSERT(sprop != child);
+ if (SPROP_MATCH(sprop, child)) {
+ /*
+ * Duplicate child, see comment above. Once again, we
+ * must let duplicates created by deletion pile up in a
+ * kids-chunk-list, in order to find them when sweeping
+ * and thereby avoid dangling parent pointers.
+ */
+ JS_RUNTIME_METER(rt, duplicatePropTreeNodes);
+ }
+
+ chunk = NewPropTreeKidsChunk(rt);
+ if (!chunk)
+ return JS_FALSE;
+ parent->kids = CHUNK_TO_KIDS(chunk);
+ chunk->kids[0] = sprop;
+ childp = &chunk->kids[1];
+ }
+ }
+ insert:
+ *childp = child;
+ }
+
+ child->parent = parent;
+ return JS_TRUE;
+}
+
+/* NB: Called with the runtime lock held. */
+static void
+RemovePropertyTreeChild(JSRuntime *rt, JSScopeProperty *child)
+{
+ JSPropertyTreeEntry *entry;
+ JSScopeProperty *parent, *kids, *kid;
+ PropTreeKidsChunk *list, *chunk, **chunkp, *lastChunk;
+ uintN i, j;
+
+ parent = child->parent;
+ if (!parent) {
+ /*
+ * Don't remove child if it is not in rt->propertyTreeHash, but only
+ * matches a root child in the table that has compatible members. See
+ * the "Duplicate child" comments in InsertPropertyTreeChild, above.
+ */
+ entry = (JSPropertyTreeEntry *)
+ JS_DHashTableOperate(&rt->propertyTreeHash, child, JS_DHASH_LOOKUP);
+
+ if (entry->child == child)
+ JS_DHashTableRawRemove(&rt->propertyTreeHash, &entry->hdr);
+ } else {
+ kids = parent->kids;
+ if (KIDS_IS_CHUNKY(kids)) {
+ list = chunk = KIDS_TO_CHUNK(kids);
+ chunkp = &list;
+
+ do {
+ for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
+ if (chunk->kids[i] == child) {
+ lastChunk = chunk;
+ if (!lastChunk->next) {
+ j = i + 1;
+ } else {
+ j = 0;
+ do {
+ chunkp = &lastChunk->next;
+ lastChunk = *chunkp;
+ } while (lastChunk->next);
+ }
+ for (; j < MAX_KIDS_PER_CHUNK; j++) {
+ if (!lastChunk->kids[j])
+ break;
+ }
+ --j;
+ if (chunk != lastChunk || j > i)
+ chunk->kids[i] = lastChunk->kids[j];
+ lastChunk->kids[j] = NULL;
+ if (j == 0) {
+ *chunkp = NULL;
+ if (!list)
+ parent->kids = NULL;
+ DestroyPropTreeKidsChunk(rt, lastChunk);
+ }
+ return;
+ }
+ }
+
+ chunkp = &chunk->next;
+ } while ((chunk = *chunkp) != NULL);
+ } else {
+ kid = kids;
+ if (kid == child)
+ parent->kids = NULL;
+ }
+ }
+}
+
+/*
+ * Called *without* the runtime lock held, this function acquires that lock
+ * only when inserting a new child. Thus there may be races to find or add
+ * a node that result in duplicates. We expect such races to be rare!
+ */
+static JSScopeProperty *
+GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
+ JSScopeProperty *child)
+{
+ JSRuntime *rt;
+ JSPropertyTreeEntry *entry;
+ JSScopeProperty *sprop;
+ PropTreeKidsChunk *chunk;
+ uintN i;
+
+ rt = cx->runtime;
+ if (!parent) {
+ JS_LOCK_RUNTIME(rt);
+
+ entry = (JSPropertyTreeEntry *)
+ JS_DHashTableOperate(&rt->propertyTreeHash, child, JS_DHASH_ADD);
+ if (!entry)
+ goto out_of_memory;
+
+ sprop = entry->child;
+ if (sprop)
+ goto out;
+ } else {
+ /*
+ * Because chunks are appended at the end and never deleted except by
+ * the GC, we can search without taking the runtime lock. We may miss
+ * a matching sprop added by another thread, and make a duplicate one,
+ * but that is an unlikely, therefore small, cost. The property tree
+ * has extremely low fan-out below its root in popular embeddings with
+ * real-world workloads.
+ *
+ * If workload changes so as to increase fan-out significantly below
+ * the property tree root, we'll want to add another tag bit stored in
+ * parent->kids that indicates a JSDHashTable pointer.
+ */
+ entry = NULL;
+ sprop = parent->kids;
+ if (sprop) {
+ if (KIDS_IS_CHUNKY(sprop)) {
+ chunk = KIDS_TO_CHUNK(sprop);
+ do {
+ for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
+ sprop = chunk->kids[i];
+ if (!sprop)
+ goto not_found;
+
+ if (SPROP_MATCH(sprop, child))
+ return sprop;
+ }
+ } while ((chunk = chunk->next) != NULL);
+ } else {
+ if (SPROP_MATCH(sprop, child))
+ return sprop;
+ }
+ }
+
+ not_found:
+ JS_LOCK_RUNTIME(rt);
+ }
+
+ sprop = NewScopeProperty(rt);
+ if (!sprop)
+ goto out_of_memory;
+
+ sprop->id = child->id;
+ sprop->getter = child->getter;
+ sprop->setter = child->setter;
+ sprop->slot = child->slot;
+ sprop->attrs = child->attrs;
+ sprop->flags = child->flags;
+ sprop->shortid = child->shortid;
+ sprop->parent = sprop->kids = NULL;
+ if (!parent) {
+ entry->child = sprop;
+ } else {
+ if (!InsertPropertyTreeChild(rt, parent, sprop))
+ goto out_of_memory;
+ }
+
+out:
+ JS_UNLOCK_RUNTIME(rt);
+ return sprop;
+
+out_of_memory:
+ JS_UNLOCK_RUNTIME(rt);
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+}
+
+#ifdef DEBUG_notbrendan
+#define CHECK_ANCESTOR_LINE(scope, sparse) \
+ JS_BEGIN_MACRO \
+ if ((scope)->table) CheckAncestorLine(scope, sparse); \
+ JS_END_MACRO
+
+static void
+CheckAncestorLine(JSScope *scope, JSBool sparse)
+{
+ uint32 size;
+ JSScopeProperty **spp, **start, **end, *ancestorLine, *sprop, *aprop;
+ uint32 entryCount, ancestorCount;
+
+ ancestorLine = SCOPE_LAST_PROP(scope);
+ if (ancestorLine)
+ JS_ASSERT(SCOPE_HAS_PROPERTY(scope, ancestorLine));
+
+ entryCount = 0;
+ size = SCOPE_CAPACITY(scope);
+ start = scope->table;
+ for (spp = start, end = start + size; spp < end; spp++) {
+ sprop = SPROP_FETCH(spp);
+ if (sprop) {
+ entryCount++;
+ for (aprop = ancestorLine; aprop; aprop = aprop->parent) {
+ if (aprop == sprop)
+ break;
+ }
+ JS_ASSERT(aprop);
+ }
+ }
+ JS_ASSERT(entryCount == scope->entryCount);
+
+ ancestorCount = 0;
+ for (sprop = ancestorLine; sprop; sprop = sprop->parent) {
+ if (SCOPE_HAD_MIDDLE_DELETE(scope) &&
+ !SCOPE_HAS_PROPERTY(scope, sprop)) {
+ JS_ASSERT(sparse || (sprop->flags & SPROP_IS_DUPLICATE));
+ continue;
+ }
+ ancestorCount++;
+ }
+ JS_ASSERT(ancestorCount == scope->entryCount);
+}
+#else
+#define CHECK_ANCESTOR_LINE(scope, sparse) /* nothing */
+#endif
+
+static void
+ReportReadOnlyScope(JSContext *cx, JSScope *scope)
+{
+ JSString *str;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(scope->object));
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_READ_ONLY,
+ str
+ ? JS_GetStringBytes(str)
+ : LOCKED_OBJ_GET_CLASS(scope->object)->name);
+}
+
+JSScopeProperty *
+js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
+ JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
+ uintN attrs, uintN flags, intN shortid)
+{
+ JSScopeProperty **spp, *sprop, *overwriting, **spvec, **spp2, child;
+ uint32 size, splen, i;
+ int change;
+
+ JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+
+ /*
+ * You can't add properties to a sealed scope. But note well that you can
+ * change property attributes in a sealed scope, even though that replaces
+ * a JSScopeProperty * in the scope's hash table -- but no id is added, so
+ * the scope remains sealed.
+ */
+ if (SCOPE_IS_SEALED(scope)) {
+ ReportReadOnlyScope(cx, scope);
+ return NULL;
+ }
+
+ /*
+ * Normalize stub getter and setter values for faster is-stub testing in
+ * the SPROP_CALL_[GS]ETTER macros.
+ */
+ if (getter == JS_PropertyStub)
+ getter = NULL;
+ if (setter == JS_PropertyStub)
+ setter = NULL;
+
+ /*
+ * Search for id in order to claim its entry, allocating a property tree
+ * node if one doesn't already exist for our parameters.
+ */
+ spp = js_SearchScope(scope, id, JS_TRUE);
+ sprop = overwriting = SPROP_FETCH(spp);
+ if (!sprop) {
+ /* Check whether we need to grow, if the load factor is >= .75. */
+ size = SCOPE_CAPACITY(scope);
+ if (scope->entryCount + scope->removedCount >= size - (size >> 2)) {
+ if (scope->removedCount >= size >> 2) {
+ METER(compresses);
+ change = 0;
+ } else {
+ METER(grows);
+ change = 1;
+ }
+ if (!ChangeScope(cx, scope, change) &&
+ scope->entryCount + scope->removedCount == size - 1) {
+ METER(addFailures);
+ return NULL;
+ }
+ spp = js_SearchScope(scope, id, JS_TRUE);
+ JS_ASSERT(!SPROP_FETCH(spp));
+ }
+ } else {
+ /* Property exists: js_SearchScope must have returned a valid entry. */
+ JS_ASSERT(!SPROP_IS_REMOVED(*spp));
+
+ /*
+ * If all property members match, this is a redundant add and we can
+ * return early. If the caller wants to allocate a slot, but doesn't
+ * care which slot, copy sprop->slot into slot so we can match sprop,
+ * if all other members match.
+ */
+ if (!(attrs & JSPROP_SHARED) &&
+ slot == SPROP_INVALID_SLOT &&
+ SPROP_HAS_VALID_SLOT(sprop, scope)) {
+ slot = sprop->slot;
+ }
+ if (SPROP_MATCH_PARAMS_AFTER_ID(sprop, getter, setter, slot, attrs,
+ flags, shortid)) {
+ METER(redundantAdds);
+ return sprop;
+ }
+
+ /*
+ * Duplicate formal parameters require us to leave the old property
+ * on the ancestor line, so the decompiler can find it, even though
+ * its entry in scope->table is overwritten to point at a new property
+ * descending from the old one. The SPROP_IS_DUPLICATE flag helps us
+ * cope with the consequent disparity between ancestor line height and
+ * scope->entryCount.
+ */
+ if (flags & SPROP_IS_DUPLICATE) {
+ sprop->flags |= SPROP_IS_DUPLICATE;
+ } else {
+ /*
+ * If we are clearing sprop to force an existing property to be
+ * overwritten (apart from a duplicate formal parameter), we must
+ * unlink it from the ancestor line at scope->lastProp, lazily if
+ * sprop is not lastProp. And we must remove the entry at *spp,
+ * precisely so the lazy "middle delete" fixup code further below
+ * won't find sprop in scope->table, in spite of sprop being on
+ * the ancestor line.
+ *
+ * When we finally succeed in finding or creating a new sprop
+ * and storing its pointer at *spp, we'll use the |overwriting|
+ * local saved when we first looked up id to decide whether we're
+ * indeed creating a new entry, or merely overwriting an existing
+ * property.
+ */
+ if (sprop == SCOPE_LAST_PROP(scope)) {
+ do {
+ SCOPE_REMOVE_LAST_PROP(scope);
+ if (!SCOPE_HAD_MIDDLE_DELETE(scope))
+ break;
+ sprop = SCOPE_LAST_PROP(scope);
+ } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop));
+ } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) {
+ /*
+ * If we have no hash table yet, we need one now. The middle
+ * delete code is simple-minded that way!
+ */
+ if (!scope->table) {
+ if (!CreateScopeTable(scope)) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ spp = js_SearchScope(scope, id, JS_TRUE);
+ sprop = overwriting = SPROP_FETCH(spp);
+ }
+ SCOPE_SET_MIDDLE_DELETE(scope);
+ }
+ }
+
+ /*
+ * If we fail later on trying to find or create a new sprop, we will
+ * goto fail_overwrite and restore *spp from |overwriting|. Note that
+ * we don't bother to keep scope->removedCount in sync, because we'll
+ * fix up *spp and scope->entryCount shortly, no matter how control
+ * flow returns from this function.
+ */
+ if (scope->table)
+ SPROP_STORE_PRESERVING_COLLISION(spp, NULL);
+ scope->entryCount--;
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+ sprop = NULL;
+ }
+
+ if (!sprop) {
+ /*
+ * If properties were deleted from the middle of the list starting at
+ * scope->lastProp, we may need to fork the property tree and squeeze
+ * all deleted properties out of scope's ancestor line. Otherwise we
+ * risk adding a node with the same id as a "middle" node, violating
+ * the rule that properties along an ancestor line have distinct ids
+ * (unless flagged SPROP_IS_DUPLICATE).
+ */
+ if (SCOPE_HAD_MIDDLE_DELETE(scope)) {
+ JS_ASSERT(scope->table);
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+
+ splen = scope->entryCount;
+ if (splen == 0) {
+ JS_ASSERT(scope->lastProp == NULL);
+ } else {
+ /*
+ * Enumerate live entries in scope->table using a temporary
+ * vector, by walking the (possibly sparse, due to deletions)
+ * ancestor line from scope->lastProp.
+ */
+ spvec = (JSScopeProperty **)
+ JS_malloc(cx, SCOPE_TABLE_NBYTES(splen));
+ if (!spvec)
+ goto fail_overwrite;
+ i = splen;
+ sprop = SCOPE_LAST_PROP(scope);
+ JS_ASSERT(sprop);
+ do {
+ /*
+ * NB: test SCOPE_GET_PROPERTY, not SCOPE_HAS_PROPERTY --
+ * the latter insists that sprop->id maps to sprop, while
+ * the former simply tests whether sprop->id is bound in
+ * scope. We must allow for duplicate formal parameters
+ * along the ancestor line, and fork them as needed.
+ */
+ if (!SCOPE_GET_PROPERTY(scope, sprop->id))
+ continue;
+
+ JS_ASSERT(sprop != overwriting);
+ if (i == 0) {
+ /*
+ * If our original splen estimate, scope->entryCount,
+ * is less than the ancestor line height, there must
+ * be duplicate formal parameters in this (function
+ * object) scope. Count remaining ancestors in order
+ * to realloc spvec.
+ */
+ JSScopeProperty *tmp = sprop;
+ do {
+ if (SCOPE_GET_PROPERTY(scope, tmp->id))
+ i++;
+ } while ((tmp = tmp->parent) != NULL);
+ spp2 = (JSScopeProperty **)
+ JS_realloc(cx, spvec, SCOPE_TABLE_NBYTES(splen+i));
+ if (!spp2) {
+ JS_free(cx, spvec);
+ goto fail_overwrite;
+ }
+
+ spvec = spp2;
+ memmove(spvec + i, spvec, SCOPE_TABLE_NBYTES(splen));
+ splen += i;
+ }
+
+ spvec[--i] = sprop;
+ } while ((sprop = sprop->parent) != NULL);
+ JS_ASSERT(i == 0);
+
+ /*
+ * Now loop forward through spvec, forking the property tree
+ * whenever we see a "parent gap" due to deletions from scope.
+ * NB: sprop is null on first entry to the loop body.
+ */
+ do {
+ if (spvec[i]->parent == sprop) {
+ sprop = spvec[i];
+ } else {
+ sprop = GetPropertyTreeChild(cx, sprop, spvec[i]);
+ if (!sprop) {
+ JS_free(cx, spvec);
+ goto fail_overwrite;
+ }
+
+ spp2 = js_SearchScope(scope, sprop->id, JS_FALSE);
+ JS_ASSERT(SPROP_FETCH(spp2) == spvec[i]);
+ SPROP_STORE_PRESERVING_COLLISION(spp2, sprop);
+ }
+ } while (++i < splen);
+ JS_free(cx, spvec);
+
+ /*
+ * Now sprop points to the last property in scope, where the
+ * ancestor line from sprop to the root is dense w.r.t. scope:
+ * it contains no nodes not mapped by scope->table, apart from
+ * any stinking ECMA-mandated duplicate formal parameters.
+ */
+ scope->lastProp = sprop;
+ CHECK_ANCESTOR_LINE(scope, JS_FALSE);
+ JS_RUNTIME_METER(cx->runtime, middleDeleteFixups);
+ }
+
+ SCOPE_CLR_MIDDLE_DELETE(scope);
+ }
+
+ /*
+ * Aliases share another property's slot, passed in the |slot| param.
+ * Shared properties have no slot. Unshared properties that do not
+ * alias another property's slot get one here, but may lose it due to
+ * a JS_ClearScope call.
+ */
+ if (!(flags & SPROP_IS_ALIAS)) {
+ if (attrs & JSPROP_SHARED) {
+ slot = SPROP_INVALID_SLOT;
+ } else {
+ /*
+ * We may have set slot from a nearly-matching sprop, above.
+ * If so, we're overwriting that nearly-matching sprop, so we
+ * can reuse its slot -- we don't need to allocate a new one.
+ * Callers should therefore pass SPROP_INVALID_SLOT for all
+ * non-alias, unshared property adds.
+ */
+ if (slot != SPROP_INVALID_SLOT)
+ JS_ASSERT(overwriting);
+ else if (!js_AllocSlot(cx, scope->object, &slot))
+ goto fail_overwrite;
+ }
+ }
+
+ /*
+ * Check for a watchpoint on a deleted property; if one exists, change
+ * setter to js_watch_set.
+ * XXXbe this could get expensive with lots of watchpoints...
+ */
+ if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList) &&
+ js_FindWatchPoint(cx->runtime, scope, id)) {
+ setter = js_WrapWatchedSetter(cx, id, attrs, setter);
+ if (!setter)
+ goto fail_overwrite;
+ }
+
+ /* Find or create a property tree node labeled by our arguments. */
+ child.id = id;
+ child.getter = getter;
+ child.setter = setter;
+ child.slot = slot;
+ child.attrs = attrs;
+ child.flags = flags;
+ child.shortid = shortid;
+ sprop = GetPropertyTreeChild(cx, scope->lastProp, &child);
+ if (!sprop)
+ goto fail_overwrite;
+
+ /* Store the tree node pointer in the table entry for id. */
+ if (scope->table)
+ SPROP_STORE_PRESERVING_COLLISION(spp, sprop);
+ scope->entryCount++;
+ scope->lastProp = sprop;
+ CHECK_ANCESTOR_LINE(scope, JS_FALSE);
+ if (!overwriting) {
+ JS_RUNTIME_METER(cx->runtime, liveScopeProps);
+ JS_RUNTIME_METER(cx->runtime, totalScopeProps);
+ }
+
+ /*
+ * If we reach the hashing threshold, try to allocate scope->table.
+ * If we can't (a rare event, preceded by swapping to death on most
+ * modern OSes), stick with linear search rather than whining about
+ * this little set-back. Therefore we must test !scope->table and
+ * scope->entryCount >= SCOPE_HASH_THRESHOLD, not merely whether the
+ * entry count just reached the threshold.
+ */
+ if (!scope->table && scope->entryCount >= SCOPE_HASH_THRESHOLD)
+ (void) CreateScopeTable(scope);
+ }
+
+ METER(adds);
+ return sprop;
+
+fail_overwrite:
+ if (overwriting) {
+ /*
+ * We may or may not have forked overwriting out of scope's ancestor
+ * line, so we must check (the alternative is to set a flag above, but
+ * that hurts the common, non-error case). If we did fork overwriting
+ * out, we'll add it back at scope->lastProp. This means enumeration
+ * order can change due to a failure to overwrite an id.
+ * XXXbe very minor incompatibility
+ */
+ for (sprop = SCOPE_LAST_PROP(scope); ; sprop = sprop->parent) {
+ if (!sprop) {
+ sprop = SCOPE_LAST_PROP(scope);
+ if (overwriting->parent == sprop) {
+ scope->lastProp = overwriting;
+ } else {
+ sprop = GetPropertyTreeChild(cx, sprop, overwriting);
+ if (sprop) {
+ JS_ASSERT(sprop != overwriting);
+ scope->lastProp = sprop;
+ }
+ overwriting = sprop;
+ }
+ break;
+ }
+ if (sprop == overwriting)
+ break;
+ }
+ if (overwriting) {
+ if (scope->table)
+ SPROP_STORE_PRESERVING_COLLISION(spp, overwriting);
+ scope->entryCount++;
+ }
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+ }
+ METER(addFailures);
+ return NULL;
+}
+
+JSScopeProperty *
+js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope,
+ JSScopeProperty *sprop, uintN attrs, uintN mask,
+ JSPropertyOp getter, JSPropertyOp setter)
+{
+ JSScopeProperty child, *newsprop, **spp;
+
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+
+ /* Allow only shared (slot-less) => unshared (slot-full) transition. */
+ attrs |= sprop->attrs & mask;
+ JS_ASSERT(!((attrs ^ sprop->attrs) & JSPROP_SHARED) ||
+ !(attrs & JSPROP_SHARED));
+ if (getter == JS_PropertyStub)
+ getter = NULL;
+ if (setter == JS_PropertyStub)
+ setter = NULL;
+ if (sprop->attrs == attrs &&
+ sprop->getter == getter &&
+ sprop->setter == setter) {
+ return sprop;
+ }
+
+ child.id = sprop->id;
+ child.getter = getter;
+ child.setter = setter;
+ child.slot = sprop->slot;
+ child.attrs = attrs;
+ child.flags = sprop->flags;
+ child.shortid = sprop->shortid;
+
+ if (SCOPE_LAST_PROP(scope) == sprop) {
+ /*
+ * Optimize the case where the last property added to scope is changed
+ * to have a different attrs, getter, or setter. In the last property
+ * case, we need not fork the property tree. But since we do not call
+ * js_AddScopeProperty, we may need to allocate a new slot directly.
+ */
+ if ((sprop->attrs & JSPROP_SHARED) && !(attrs & JSPROP_SHARED)) {
+ JS_ASSERT(child.slot == SPROP_INVALID_SLOT);
+ if (!js_AllocSlot(cx, scope->object, &child.slot))
+ return NULL;
+ }
+
+ newsprop = GetPropertyTreeChild(cx, sprop->parent, &child);
+ if (newsprop) {
+ spp = js_SearchScope(scope, sprop->id, JS_FALSE);
+ JS_ASSERT(SPROP_FETCH(spp) == sprop);
+
+ if (scope->table)
+ SPROP_STORE_PRESERVING_COLLISION(spp, newsprop);
+ scope->lastProp = newsprop;
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+ }
+ } else {
+ /*
+ * Let js_AddScopeProperty handle this |overwriting| case, including
+ * the conservation of sprop->slot (if it's valid). We must not call
+ * js_RemoveScopeProperty here, it will free a valid sprop->slot and
+ * js_AddScopeProperty won't re-allocate it.
+ */
+ newsprop = js_AddScopeProperty(cx, scope, child.id,
+ child.getter, child.setter, child.slot,
+ child.attrs, child.flags, child.shortid);
+ }
+
+#ifdef DEBUG_brendan
+ if (!newsprop)
+ METER(changeFailures);
+#endif
+ return newsprop;
+}
+
+JSBool
+js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id)
+{
+ JSScopeProperty **spp, *stored, *sprop;
+ uint32 size;
+
+ JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+ if (SCOPE_IS_SEALED(scope)) {
+ ReportReadOnlyScope(cx, scope);
+ return JS_FALSE;
+ }
+ METER(removes);
+
+ spp = js_SearchScope(scope, id, JS_FALSE);
+ stored = *spp;
+ sprop = SPROP_CLEAR_COLLISION(stored);
+ if (!sprop) {
+ METER(uselessRemoves);
+ return JS_TRUE;
+ }
+
+ /* Convert from a list to a hash so we can handle "middle deletes". */
+ if (!scope->table && sprop != scope->lastProp) {
+ if (!CreateScopeTable(scope)) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ spp = js_SearchScope(scope, id, JS_FALSE);
+ stored = *spp;
+ sprop = SPROP_CLEAR_COLLISION(stored);
+ }
+
+ /* First, if sprop is unshared and not cleared, free its slot number. */
+ if (SPROP_HAS_VALID_SLOT(sprop, scope))
+ js_FreeSlot(cx, scope->object, sprop->slot);
+
+ /* Next, remove id by setting its entry to a removed or free sentinel. */
+ if (SPROP_HAD_COLLISION(stored)) {
+ JS_ASSERT(scope->table);
+ *spp = SPROP_REMOVED;
+ scope->removedCount++;
+ } else {
+ METER(removeFrees);
+ if (scope->table)
+ *spp = NULL;
+ }
+ scope->entryCount--;
+ JS_RUNTIME_UNMETER(cx->runtime, liveScopeProps);
+
+ /* Update scope->lastProp directly, or set its deferred update flag. */
+ if (sprop == SCOPE_LAST_PROP(scope)) {
+ do {
+ SCOPE_REMOVE_LAST_PROP(scope);
+ if (!SCOPE_HAD_MIDDLE_DELETE(scope))
+ break;
+ sprop = SCOPE_LAST_PROP(scope);
+ } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop));
+ } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) {
+ SCOPE_SET_MIDDLE_DELETE(scope);
+ }
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+
+ /* Last, consider shrinking scope's table if its load factor is <= .25. */
+ size = SCOPE_CAPACITY(scope);
+ if (size > MIN_SCOPE_SIZE && scope->entryCount <= size >> 2) {
+ METER(shrinks);
+ (void) ChangeScope(cx, scope, -1);
+ }
+
+ return JS_TRUE;
+}
+
+void
+js_ClearScope(JSContext *cx, JSScope *scope)
+{
+ CHECK_ANCESTOR_LINE(scope, JS_TRUE);
+#ifdef DEBUG
+ JS_LOCK_RUNTIME_VOID(cx->runtime,
+ cx->runtime->liveScopeProps -= scope->entryCount);
+#endif
+
+ if (scope->table)
+ free(scope->table);
+ SCOPE_CLR_MIDDLE_DELETE(scope);
+ InitMinimalScope(scope);
+}
+
+#ifdef DEBUG_brendan
+
+#include <stdio.h>
+#include <math.h>
+
+uint32 js_nkids_max;
+uint32 js_nkids_sum;
+double js_nkids_sqsum;
+uint32 js_nkids_hist[11];
+
+static void
+MeterKidCount(uintN nkids)
+{
+ if (nkids) {
+ js_nkids_sum += nkids;
+ js_nkids_sqsum += (double)nkids * nkids;
+ if (nkids > js_nkids_max)
+ js_nkids_max = nkids;
+ }
+ js_nkids_hist[JS_MIN(nkids, 10)]++;
+}
+
+static void
+MeterPropertyTree(JSScopeProperty *node)
+{
+ uintN i, nkids;
+ JSScopeProperty *kids, *kid;
+ PropTreeKidsChunk *chunk;
+
+ nkids = 0;
+ kids = node->kids;
+ if (kids) {
+ if (KIDS_IS_CHUNKY(kids)) {
+ for (chunk = KIDS_TO_CHUNK(kids); chunk; chunk = chunk->next) {
+ for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
+ kid = chunk->kids[i];
+ if (!kid)
+ break;
+ MeterPropertyTree(kid);
+ nkids++;
+ }
+ }
+ } else {
+ MeterPropertyTree(kids);
+ nkids = 1;
+ }
+ }
+
+ MeterKidCount(nkids);
+}
+
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
+ void *arg)
+{
+ JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *)hdr;
+
+ MeterPropertyTree(entry->child);
+ return JS_DHASH_NEXT;
+}
+
+#endif /* DEBUG_brendan */
+
+void
+js_SweepScopeProperties(JSRuntime *rt)
+{
+ JSArena **ap, *a;
+ JSScopeProperty *limit, *sprop, *parent, *kids, *kid;
+ uintN liveCount;
+ PropTreeKidsChunk *chunk, *nextChunk;
+ uintN i;
+
+#ifdef DEBUG_brendan
+ uint32 livePropCapacity = 0, totalLiveCount = 0;
+ static FILE *logfp;
+ if (!logfp)
+ logfp = fopen("/tmp/proptree.stats", "a");
+
+ MeterKidCount(rt->propertyTreeHash.entryCount);
+ JS_DHashTableEnumerate(&rt->propertyTreeHash, js_MeterPropertyTree, NULL);
+
+ {
+ double mean = 0., var = 0., sigma = 0.;
+ double nodesum = rt->livePropTreeNodes;
+ double kidsum = js_nkids_sum;
+ if (nodesum > 0 && kidsum >= 0) {
+ mean = kidsum / nodesum;
+ var = nodesum * js_nkids_sqsum - kidsum * kidsum;
+ if (var < 0.0 || nodesum <= 1)
+ var = 0.0;
+ else
+ var /= nodesum * (nodesum - 1);
+
+ /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
+ sigma = (var != 0.) ? sqrt(var) : 0.;
+ }
+
+ fprintf(logfp,
+ "props %u nodes %g beta %g meankids %g sigma %g max %u",
+ rt->liveScopeProps, nodesum, nodesum / rt->liveScopeProps,
+ mean, sigma, js_nkids_max);
+ }
+
+ fprintf(logfp, " histogram %u %u %u %u %u %u %u %u %u %u %u",
+ js_nkids_hist[0], js_nkids_hist[1],
+ js_nkids_hist[2], js_nkids_hist[3],
+ js_nkids_hist[4], js_nkids_hist[5],
+ js_nkids_hist[6], js_nkids_hist[7],
+ js_nkids_hist[8], js_nkids_hist[9],
+ js_nkids_hist[10]);
+ js_nkids_sum = js_nkids_max = 0;
+ js_nkids_sqsum = 0;
+ memset(js_nkids_hist, 0, sizeof js_nkids_hist);
+#endif
+
+ ap = &rt->propertyArenaPool.first.next;
+ while ((a = *ap) != NULL) {
+ limit = (JSScopeProperty *) a->avail;
+ liveCount = 0;
+ for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) {
+ /* If the id is null, sprop is already on the freelist. */
+ if (sprop->id == JSVAL_NULL)
+ continue;
+
+ /* If the mark bit is set, sprop is alive, so we skip it. */
+ if (sprop->flags & SPROP_MARK) {
+ sprop->flags &= ~SPROP_MARK;
+ liveCount++;
+ continue;
+ }
+
+ /* Ok, sprop is garbage to collect: unlink it from its parent. */
+ RemovePropertyTreeChild(rt, sprop);
+
+ /* Take care to reparent all sprop's kids to their grandparent. */
+ kids = sprop->kids;
+ if (kids) {
+ sprop->kids = NULL;
+ parent = sprop->parent;
+ if (KIDS_IS_CHUNKY(kids)) {
+ chunk = KIDS_TO_CHUNK(kids);
+ do {
+ for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
+ kid = chunk->kids[i];
+ if (!kid)
+ break;
+ JS_ASSERT(kid->parent == sprop);
+ InsertPropertyTreeChild(rt, parent, kid);
+ }
+ nextChunk = chunk->next;
+ DestroyPropTreeKidsChunk(rt, chunk);
+ } while ((chunk = nextChunk) != NULL);
+ } else {
+ kid = kids;
+ InsertPropertyTreeChild(rt, parent, kid);
+ }
+ }
+
+ /* Clear id so we know (above) that sprop is on the freelist. */
+ sprop->id = JSVAL_NULL;
+ FREENODE_INSERT(rt->propertyFreeList, sprop);
+ JS_RUNTIME_UNMETER(rt, livePropTreeNodes);
+ }
+
+ /* If a contains no live properties, return it to the malloc heap. */
+ if (liveCount == 0) {
+ for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++)
+ FREENODE_REMOVE(sprop);
+ JS_ARENA_DESTROY(&rt->propertyArenaPool, a, ap);
+ } else {
+#ifdef DEBUG_brendan
+ livePropCapacity += limit - (JSScopeProperty *) a->base;
+ totalLiveCount += liveCount;
+#endif
+ ap = &a->next;
+ }
+ }
+
+#ifdef DEBUG_brendan
+ fprintf(logfp, " arenautil %g%%\n",
+ (totalLiveCount * 100.) / livePropCapacity);
+ fflush(logfp);
+#endif
+}
+
+JSBool
+js_InitPropertyTree(JSRuntime *rt)
+{
+ if (!JS_DHashTableInit(&rt->propertyTreeHash, &PropertyTreeHashOps, NULL,
+ sizeof(JSPropertyTreeEntry), JS_DHASH_MIN_SIZE)) {
+ rt->propertyTreeHash.ops = NULL;
+ return JS_FALSE;
+ }
+ JS_InitArenaPool(&rt->propertyArenaPool, "properties",
+ 256 * sizeof(JSScopeProperty), sizeof(void *));
+ return JS_TRUE;
+}
+
+void
+js_FinishPropertyTree(JSRuntime *rt)
+{
+ if (rt->propertyTreeHash.ops) {
+ JS_DHashTableFinish(&rt->propertyTreeHash);
+ rt->propertyTreeHash.ops = NULL;
+ }
+ JS_FinishArenaPool(&rt->propertyArenaPool);
+}
diff --git a/src/dom/js/jsscope.h b/src/dom/js/jsscope.h
new file mode 100644
index 000000000..4f66441b4
--- /dev/null
+++ b/src/dom/js/jsscope.h
@@ -0,0 +1,386 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsscope_h___
+#define jsscope_h___
+/*
+ * JS symbol tables.
+ */
+#include "jstypes.h"
+#include "jsobj.h"
+#include "jsprvtd.h"
+#include "jspubtd.h"
+
+#ifdef JS_THREADSAFE
+# include "jslock.h"
+#endif
+
+/*
+ * Given P independent, non-unique properties each of size S words mapped by
+ * all scopes in a runtime, construct a property tree of N nodes each of size
+ * S+L words (L for tree linkage). A nominal L value is 2 for leftmost-child
+ * and right-sibling links. We hope that the N < P by enough that the space
+ * overhead of L, and the overhead of scope entries pointing at property tree
+ * nodes, is worth it.
+ *
+ * The tree construction goes as follows. If any empty scope in the runtime
+ * has a property X added to it, find or create a node under the tree root
+ * labeled X, and set scope->lastProp to point at that node. If any non-empty
+ * scope whose most recently added property is labeled Y has another property
+ * labeled Z added, find or create a node for Z under the node that was added
+ * for Y, and set scope->lastProp to point at that node.
+ *
+ * A property is labeled by its members' values: id, getter, setter, slot,
+ * attributes, tiny or short id, and a field telling for..in order. Note that
+ * labels are not unique in the tree, but they are unique among a node's kids
+ * (barring rare and benign multi-threaded race condition outcomes, see below)
+ * and along any ancestor line from the tree root to a given leaf node (except
+ * for the hard case of duplicate formal parameters to a function).
+ *
+ * Thus the root of the tree represents all empty scopes, and the first ply
+ * of the tree represents all scopes containing one property, etc. Each node
+ * in the tree can stand for any number of scopes having the same ordered set
+ * of properties, where that node was the last added to the scope. (We need
+ * not store the root of the tree as a node, and do not -- all we need are
+ * links to its kids.)
+ *
+ * Sidebar on for..in loop order: ECMA requires no particular order, but this
+ * implementation has promised and delivered property definition order, and
+ * compatibility is king. We could use an order number per property, which
+ * would require a sort in js_Enumerate, and an entry order generation number
+ * per scope. An order number beats a list, which should be doubly-linked for
+ * O(1) delete. An even better scheme is to use a parent link in the property
+ * tree, so that the ancestor line can be iterated from scope->lastProp when
+ * filling in a JSIdArray from back to front. This parent link also helps the
+ * GC to sweep properties iteratively.
+ *
+ * What if a property Y is deleted from a scope? If Y is the last property in
+ * the scope, we simply adjust the scope's lastProp member after we remove the
+ * scope's hash-table entry pointing at that property node. The parent link
+ * mentioned in the for..in sidebar above makes this adjustment O(1). But if
+ * Y comes between X and Z in the scope, then we might have to "fork" the tree
+ * at X, leaving X->Y->Z in case other scopes have those properties added in
+ * that order; and to finish the fork, we'd add a node labeled Z with the path
+ * X->Z, if it doesn't exist. This could lead to lots of extra nodes, and to
+ * O(n^2) growth when deleting lots of properties.
+ *
+ * Rather, for O(1) growth all around, we should share the path X->Y->Z among
+ * scopes having those three properties added in that order, and among scopes
+ * having only X->Z where Y was deleted. All such scopes have a lastProp that
+ * points to the Z child of Y. But a scope in which Y was deleted does not
+ * have a table entry for Y, and when iterating that scope by traversing the
+ * ancestor line from Z, we will have to test for a table entry for each node,
+ * skipping nodes that lack entries.
+ *
+ * What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice.
+ * Therefore we must fork in such a case, if not earlier. Because delete is
+ * "bursty", we should not fork eagerly. Delaying a fork till we are at risk
+ * of adding Y after it was deleted already requires a flag in the JSScope, to
+ * wit, SCOPE_MIDDLE_DELETE.
+ *
+ * What about thread safety? If the property tree operations done by requests
+ * are find-node and insert-node, then the only hazard is duplicate insertion.
+ * This is harmless except for minor bloat. When all requests have ended or
+ * been suspended, the GC is free to sweep the tree after marking all nodes
+ * reachable from scopes, performing remove-node operations as needed. Note
+ * also that the stable storage of the property nodes during active requests
+ * permits the property cache (see jsinterp.h) to dereference JSScopeProperty
+ * weak references safely.
+ *
+ * Is the property tree worth it compared to property storage in each table's
+ * entries? To decide, we must find the relation <> between the words used
+ * with a property tree and the words required without a tree.
+ *
+ * Model all scopes as one super-scope of capacity T entries (T a power of 2).
+ * Let alpha be the load factor of this double hash-table. With the property
+ * tree, each entry in the table is a word-sized pointer to a node that can be
+ * shared by many scopes. But all such pointers are overhead compared to the
+ * situation without the property tree, where the table stores property nodes
+ * directly, as entries each of size S words. With the property tree, we need
+ * L=2 extra words per node for siblings and kids pointers. Without the tree,
+ * (1-alpha)*S*T words are wasted on free or removed sentinel-entries required
+ * by double hashing.
+ *
+ * Therefore,
+ *
+ * (property tree) <> (no property tree)
+ * N*(S+L) + T <> S*T
+ * N*(S+L) + T <> P*S + (1-alpha)*S*T
+ * N*(S+L) + alpha*T + (1-alpha)*T <> P*S + (1-alpha)*S*T
+ *
+ * Note that P is alpha*T by definition, so
+ *
+ * N*(S+L) + P + (1-alpha)*T <> P*S + (1-alpha)*S*T
+ * N*(S+L) <> P*S - P + (1-alpha)*S*T - (1-alpha)*T
+ * N*(S+L) <> (P + (1-alpha)*T) * (S-1)
+ * N*(S+L) <> (P + (1-alpha)*P/alpha) * (S-1)
+ * N*(S+L) <> P * (1/alpha) * (S-1)
+ *
+ * Let N = P*beta for a compression ratio beta, beta <= 1:
+ *
+ * P*beta*(S+L) <> P * (1/alpha) * (S-1)
+ * beta*(S+L) <> (S-1)/alpha
+ * beta <> (S-1)/((S+L)*alpha)
+ *
+ * For S = 6 (32-bit architectures) and L = 2, the property tree wins iff
+ *
+ * beta < 5/(8*alpha)
+ *
+ * We ensure that alpha <= .75, so the property tree wins if beta < .83_. An
+ * average beta from recent Mozilla browser startups was around .6.
+ *
+ * Can we reduce L? Observe that the property tree degenerates into a list of
+ * lists if at most one property Y follows X in all scopes. In or near such a
+ * case, we waste a word on the right-sibling link outside of the root ply of
+ * the tree. Note also that the root ply tends to be large, so O(n^2) growth
+ * searching it is likely, indicating the need for hashing (but with increased
+ * thread safety costs).
+ *
+ * If only K out of N nodes in the property tree have more than one child, we
+ * could eliminate the sibling link and overlay a children list or hash-table
+ * pointer on the leftmost-child link (which would then be either null or an
+ * only-child link; the overlay could be tagged in the low bit of the pointer,
+ * or flagged elsewhere in the property tree node, although such a flag must
+ * not be considered when comparing node labels during tree search).
+ *
+ * For such a system, L = 1 + (K * averageChildrenTableSize) / N instead of 2.
+ * If K << N, L approaches 1 and the property tree wins if beta < .95.
+ *
+ * We observe that fan-out below the root ply of the property tree appears to
+ * have extremely low degree (see the MeterPropertyTree code that histograms
+ * child-counts in jsscope.c), so instead of a hash-table we use a linked list
+ * of child node pointer arrays ("kid chunks"). The details are isolated in
+ * jsscope.c; others must treat JSScopeProperty.kids as opaque. We leave it
+ * strongly typed for debug-ability of the common (null or one-kid) cases.
+ *
+ * One final twist (can you stand it?): the mean number of entries per scope
+ * in Mozilla is < 5, with a large standard deviation (~8). Instead of always
+ * allocating scope->table, we leave it null while initializing all the other
+ * scope members as if it were non-null and minimal-length. Until a property
+ * is added that crosses the threshold of 6 or more entries for hashing, or
+ * until a "middle delete" occurs, we use linear search from scope->lastProp
+ * to find a given id, and save on the space overhead of a hash table.
+ */
+
+struct JSScope {
+ JSObjectMap map; /* base class state */
+ JSObject *object; /* object that owns this scope */
+ uint16 flags; /* flags, see below */
+ int16 hashShift; /* multiplicative hash shift */
+ uint32 entryCount; /* number of entries in table */
+ uint32 removedCount; /* removed entry sentinels in table */
+ JSScopeProperty **table; /* table of ptrs to shared tree nodes */
+ JSScopeProperty *lastProp; /* pointer to last property added */
+#ifdef JS_THREADSAFE
+ JSContext *ownercx; /* creating context, NULL if shared */
+ JSThinLock lock; /* binary semaphore protecting scope */
+ union { /* union lockful and lock-free state: */
+ jsrefcount count; /* lock entry count for reentrancy */
+ JSScope *link; /* next link in rt->scopeSharingTodo */
+ } u;
+#ifdef DEBUG
+ const char *file[4]; /* file where lock was (re-)taken */
+ unsigned int line[4]; /* line where lock was (re-)taken */
+#endif
+#endif
+};
+
+#define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
+
+/* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
+#define SCOPE_CAPACITY(scope) JS_BIT(JS_DHASH_BITS-(scope)->hashShift)
+
+/* Scope flags and some macros to hide them from other files than jsscope.c. */
+#define SCOPE_MIDDLE_DELETE 0x0001
+#define SCOPE_SEALED 0x0002
+
+#define SCOPE_HAD_MIDDLE_DELETE(scope) ((scope)->flags & SCOPE_MIDDLE_DELETE)
+#define SCOPE_SET_MIDDLE_DELETE(scope) ((scope)->flags |= SCOPE_MIDDLE_DELETE)
+#define SCOPE_CLR_MIDDLE_DELETE(scope) ((scope)->flags &= ~SCOPE_MIDDLE_DELETE)
+
+#define SCOPE_IS_SEALED(scope) ((scope)->flags & SCOPE_SEALED)
+#define SCOPE_SET_SEALED(scope) ((scope)->flags |= SCOPE_SEALED)
+#if 0
+/*
+ * Don't define this, it can't be done safely because JS_LOCK_OBJ will avoid
+ * taking the lock if the object owns its scope and the scope is sealed.
+ */
+#define SCOPE_CLR_SEALED(scope) ((scope)->flags &= ~SCOPE_SEALED)
+#endif
+
+/*
+ * A little information hiding for scope->lastProp, in case it ever becomes
+ * a tagged pointer again.
+ */
+#define SCOPE_LAST_PROP(scope) ((scope)->lastProp)
+#define SCOPE_REMOVE_LAST_PROP(scope) ((scope)->lastProp = \
+ (scope)->lastProp->parent)
+
+struct JSScopeProperty {
+ jsid id; /* int-tagged jsval/untagged JSAtom* */
+ JSPropertyOp getter; /* getter and setter hooks or objects */
+ JSPropertyOp setter;
+ uint32 slot; /* index in obj->slots vector */
+ uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
+ uint8 flags; /* flags, see below for defines */
+ int16 shortid; /* tinyid, or local arg/var index */
+ JSScopeProperty *parent; /* parent node, reverse for..in order */
+ JSScopeProperty *kids; /* null, single child, or a tagged ptr
+ to many-kids data structure */
+};
+
+/* JSScopeProperty pointer tag bit indicating a collision. */
+#define SPROP_COLLISION ((jsuword)1)
+#define SPROP_REMOVED ((JSScopeProperty *) SPROP_COLLISION)
+
+/* Macros to get and set sprop pointer values and collision flags. */
+#define SPROP_IS_FREE(sprop) ((sprop) == NULL)
+#define SPROP_IS_REMOVED(sprop) ((sprop) == SPROP_REMOVED)
+#define SPROP_IS_LIVE(sprop) ((sprop) > SPROP_REMOVED)
+#define SPROP_FLAG_COLLISION(spp,sprop) (*(spp) = (JSScopeProperty *) \
+ ((jsuword)(sprop) | SPROP_COLLISION))
+#define SPROP_HAD_COLLISION(sprop) ((jsuword)(sprop) & SPROP_COLLISION)
+#define SPROP_FETCH(spp) SPROP_CLEAR_COLLISION(*(spp))
+
+#define SPROP_CLEAR_COLLISION(sprop) \
+ ((JSScopeProperty *) ((jsuword)(sprop) & ~SPROP_COLLISION))
+
+#define SPROP_STORE_PRESERVING_COLLISION(spp, sprop) \
+ (*(spp) = (JSScopeProperty *) ((jsuword)(sprop) \
+ | SPROP_HAD_COLLISION(*(spp))))
+
+/* Bits stored in sprop->flags. */
+#define SPROP_MARK 0x01
+#define SPROP_IS_DUPLICATE 0x02
+#define SPROP_IS_ALIAS 0x04
+#define SPROP_HAS_SHORTID 0x08
+
+/*
+ * If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather
+ * than id when calling sprop's getter or setter.
+ */
+#define SPROP_USERID(sprop) \
+ (((sprop)->flags & SPROP_HAS_SHORTID) ? INT_TO_JSVAL((sprop)->shortid) \
+ : ID_TO_VALUE((sprop)->id))
+
+#define SPROP_INVALID_SLOT 0xffffffff
+
+#define SPROP_HAS_VALID_SLOT(sprop, scope) \
+ ((sprop)->slot < (scope)->map.freeslot)
+
+#define SPROP_CALL_GETTER(cx,sprop,getter,obj,obj2,vp) \
+ (!(getter) || \
+ (getter)(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
+#define SPROP_CALL_SETTER(cx,sprop,setter,obj,obj2,vp) \
+ (!(setter) || \
+ (setter)(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
+
+#define SPROP_GET(cx,sprop,obj,obj2,vp) \
+ (((sprop)->attrs & JSPROP_GETTER) \
+ ? js_InternalGetOrSet(cx, obj, (sprop)->id, \
+ OBJECT_TO_JSVAL((sprop)->getter), JSACC_READ, \
+ 0, 0, vp) \
+ : SPROP_CALL_GETTER(cx, sprop, (sprop)->getter, obj, obj2, vp))
+
+#define SPROP_SET(cx,sprop,obj,obj2,vp) \
+ (((sprop)->attrs & JSPROP_SETTER) \
+ ? js_InternalGetOrSet(cx, obj, (sprop)->id, \
+ OBJECT_TO_JSVAL((sprop)->setter), JSACC_WRITE, \
+ 1, vp, vp) \
+ : ((sprop)->attrs & JSPROP_GETTER) \
+ ? (JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, \
+ JSMSG_GETTER_ONLY, NULL), JS_FALSE) \
+ : SPROP_CALL_SETTER(cx, sprop, (sprop)->setter, obj, obj2, vp))
+
+/* Macro for common expression to test for shared permanent attributes. */
+#define SPROP_IS_SHARED_PERMANENT(sprop) \
+ ((~(sprop)->attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0)
+
+extern JSScope *
+js_GetMutableScope(JSContext *cx, JSObject *obj);
+
+extern JSScope *
+js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
+ JSObject *obj);
+
+extern void
+js_DestroyScope(JSContext *cx, JSScope *scope);
+
+#define ID_TO_VALUE(id) (((id) & JSVAL_INT) ? id : ATOM_KEY((JSAtom *)(id)))
+#define HASH_ID(id) (((id) & JSVAL_INT) \
+ ? (jsatomid) JSVAL_TO_INT(id) \
+ : ((JSAtom *)id)->number)
+
+extern JS_FRIEND_API(JSScopeProperty **)
+js_SearchScope(JSScope *scope, jsid id, JSBool adding);
+
+#define SCOPE_GET_PROPERTY(scope, id) \
+ SPROP_FETCH(js_SearchScope(scope, id, JS_FALSE))
+
+#define SCOPE_HAS_PROPERTY(scope, sprop) \
+ (SCOPE_GET_PROPERTY(scope, (sprop)->id) == (sprop))
+
+extern JSScopeProperty *
+js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
+ JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
+ uintN attrs, uintN flags, intN shortid);
+
+extern JSScopeProperty *
+js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope,
+ JSScopeProperty *sprop, uintN attrs, uintN mask,
+ JSPropertyOp getter, JSPropertyOp setter);
+
+extern JSBool
+js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id);
+
+extern void
+js_ClearScope(JSContext *cx, JSScope *scope);
+
+#define MARK_SCOPE_PROPERTY(sprop) ((sprop)->flags |= SPROP_MARK)
+
+extern void
+js_SweepScopeProperties(JSRuntime *rt);
+
+extern JSBool
+js_InitPropertyTree(JSRuntime *rt);
+
+extern void
+js_FinishPropertyTree(JSRuntime *rt);
+
+#endif /* jsscope_h___ */
diff --git a/src/dom/js/jsscript.c b/src/dom/js/jsscript.c
new file mode 100644
index 000000000..504cbbd6d
--- /dev/null
+++ b/src/dom/js/jsscript.c
@@ -0,0 +1,1287 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS script operations.
+ */
+#include "jsstddef.h"
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsdbgapi.h"
+#include "jsemit.h"
+#include "jsfun.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsopcode.h"
+#include "jsscript.h"
+#if JS_HAS_XDR
+#include "jsxdrapi.h"
+#endif
+
+#if JS_HAS_SCRIPT_OBJECT
+
+#if JS_HAS_TOSOURCE
+static JSBool
+script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSScript *script;
+ size_t i, j, k, n;
+ char buf[16];
+ jschar *s, *t;
+ uint32 indent;
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
+ return JS_FALSE;
+ script = (JSScript *) JS_GetPrivate(cx, obj);
+
+ /* Let n count the source string length, j the "front porch" length. */
+ j = JS_snprintf(buf, sizeof buf, "(new %s(", js_ScriptClass.name);
+ n = j + 2;
+ if (!script) {
+ /* Let k count the constructor argument string length. */
+ k = 0;
+ s = NULL; /* quell GCC overwarning */
+ } else {
+ indent = 0;
+ if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
+ return JS_FALSE;
+ str = JS_DecompileScript(cx, script, "Script.prototype.toSource",
+ (uintN)indent);
+ if (!str)
+ return JS_FALSE;
+ str = js_QuoteString(cx, str, '\'');
+ if (!str)
+ return JS_FALSE;
+ s = JSSTRING_CHARS(str);
+ k = JSSTRING_LENGTH(str);
+ n += k;
+ }
+
+ /* Allocate the source string and copy into it. */
+ t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
+ if (!t)
+ return JS_FALSE;
+ for (i = 0; i < j; i++)
+ t[i] = buf[i];
+ for (j = 0; j < k; i++, j++)
+ t[i] = s[j];
+ t[i++] = ')';
+ t[i++] = ')';
+ t[i] = 0;
+
+ /* Create and return a JS string for t. */
+ str = JS_NewUCString(cx, t, n);
+ if (!str) {
+ JS_free(cx, t);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif /* JS_HAS_TOSOURCE */
+
+static JSBool
+script_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSScript *script;
+ uint32 indent;
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
+ return JS_FALSE;
+ script = (JSScript *) JS_GetPrivate(cx, obj);
+ if (!script) {
+ *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
+ return JS_TRUE;
+ }
+
+ indent = 0;
+ if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
+ return JS_FALSE;
+ str = JS_DecompileScript(cx, script, "Script.prototype.toString",
+ (uintN)indent);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSScript *oldscript, *script;
+ JSString *str;
+ JSStackFrame *fp, *caller;
+ JSObject *scopeobj;
+ const char *file;
+ uintN line;
+ JSPrincipals *principals;
+
+ /* Make sure obj is a Script object. */
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
+ return JS_FALSE;
+
+ /* If no args, leave private undefined and return early. */
+ if (argc == 0)
+ goto out;
+
+ /* Otherwise, the first arg is the script source to compile. */
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+
+ /* Compile using the caller's scope chain, which js_Invoke passes to fp. */
+ fp = cx->fp;
+ caller = JS_GetScriptedCaller(cx, fp);
+ JS_ASSERT(!caller || fp->scopeChain == caller->scopeChain);
+
+ scopeobj = NULL;
+ if (argc >= 2) {
+ if (!js_ValueToObject(cx, argv[1], &scopeobj))
+ return JS_FALSE;
+ argv[1] = OBJECT_TO_JSVAL(scopeobj);
+ }
+ if (caller) {
+ if (!scopeobj)
+ scopeobj = caller->scopeChain;
+
+ file = caller->script->filename;
+ line = js_PCToLineNumber(cx, caller->script, caller->pc);
+ principals = JS_EvalFramePrincipals(cx, fp, caller);
+ } else {
+ file = NULL;
+ line = 0;
+ principals = NULL;
+ }
+
+ /* XXXbe set only for the compiler, which does not currently test it */
+ fp->flags |= JSFRAME_EVAL;
+
+ /* Compile the new script using the caller's scope chain, a la eval(). */
+ script = JS_CompileUCScriptForPrincipals(cx, scopeobj, principals,
+ JSSTRING_CHARS(str),
+ JSSTRING_LENGTH(str),
+ file, line);
+ if (!script)
+ return JS_FALSE;
+
+ /* Swap script for obj's old script, if any. */
+ oldscript = (JSScript *) JS_GetPrivate(cx, obj);
+ if (!JS_SetPrivate(cx, obj, script)) {
+ js_DestroyScript(cx, script);
+ return JS_FALSE;
+ }
+ if (oldscript)
+ js_DestroyScript(cx, oldscript);
+
+ script->object = obj;
+out:
+ /* Return the object. */
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+static JSBool
+script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSScript *script;
+ JSObject *scopeobj, *parent;
+ JSStackFrame *fp, *caller;
+
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
+ return JS_FALSE;
+ script = (JSScript *) JS_GetPrivate(cx, obj);
+ if (!script)
+ return JS_TRUE;
+
+ scopeobj = NULL;
+ if (argc) {
+ if (!js_ValueToObject(cx, argv[0], &scopeobj))
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(scopeobj);
+ }
+
+ /*
+ * Emulate eval() by using caller's this, var object, sharp array, etc.,
+ * all propagated by js_Execute via a non-null fourth (down) argument to
+ * js_Execute. If there is no scripted caller, js_Execute uses its second
+ * (chain) argument to set the exec frame's varobj, thisp, and scopeChain.
+ *
+ * Unlike eval, which the compiler detects, Script.prototype.exec may be
+ * called from a lightweight function, or even from native code (in which
+ * case fp->varobj and fp->scopeChain are null). If exec is called from
+ * a lightweight function, we will need to get a Call object representing
+ * its frame, to act as the var object and scope chain head.
+ */
+ fp = cx->fp;
+ caller = JS_GetScriptedCaller(cx, fp);
+ if (caller && !caller->varobj) {
+ /* Called from a lightweight function. */
+ JS_ASSERT(caller->fun && !(caller->fun->flags & JSFUN_HEAVYWEIGHT));
+
+ /* Scope chain links from Call object to callee's parent. */
+ parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(caller->argv[-2]));
+ if (!js_GetCallObject(cx, caller, parent))
+ return JS_FALSE;
+ }
+
+ if (!scopeobj) {
+ /* No scope object passed in: try to use the caller's scope chain. */
+ if (caller) {
+ /*
+ * Load caller->scopeChain after the conditional js_GetCallObject
+ * call above, which resets scopeChain as well as varobj.
+ */
+ scopeobj = caller->scopeChain;
+ } else {
+ /*
+ * Called from native code, so we don't know what scope object to
+ * use. We could use parent (see above), but Script.prototype.exec
+ * might be a shared/sealed "superglobal" method. A more general
+ * approach would use cx->globalObject, which will be the same as
+ * exec.__parent__ in the non-superglobal case. In the superglobal
+ * case it's the right object: the global, not the superglobal.
+ */
+ scopeobj = cx->globalObject;
+ }
+ }
+
+ return js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
+}
+
+#if JS_HAS_XDR
+
+static JSBool
+XDRAtomListElement(JSXDRState *xdr, JSAtomListElement *ale)
+{
+ jsval value;
+ jsatomid index;
+
+ if (xdr->mode == JSXDR_ENCODE)
+ value = ATOM_KEY(ALE_ATOM(ale));
+
+ index = ALE_INDEX(ale);
+ if (!JS_XDRUint32(xdr, &index))
+ return JS_FALSE;
+ ALE_SET_INDEX(ale, index);
+
+ if (!JS_XDRValue(xdr, &value))
+ return JS_FALSE;
+
+ if (xdr->mode == JSXDR_DECODE) {
+ if (!ALE_SET_ATOM(ale, js_AtomizeValue(xdr->cx, value, 0)))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+XDRAtomMap(JSXDRState *xdr, JSAtomMap *map)
+{
+ uint32 length;
+ uintN i;
+ JSBool ok;
+
+ if (xdr->mode == JSXDR_ENCODE)
+ length = map->length;
+
+ if (!JS_XDRUint32(xdr, &length))
+ return JS_FALSE;
+
+ if (xdr->mode == JSXDR_DECODE) {
+ JSContext *cx;
+ void *mark;
+ JSAtomList al;
+ JSAtomListElement *ale;
+
+ cx = xdr->cx;
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ATOM_LIST_INIT(&al);
+ for (i = 0; i < length; i++) {
+ JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool);
+ if (!ale ||
+ !XDRAtomListElement(xdr, ale)) {
+ if (!ale)
+ JS_ReportOutOfMemory(cx);
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return JS_FALSE;
+ }
+ ALE_SET_NEXT(ale, al.list);
+ al.count++;
+ al.list = ale;
+ }
+ ok = js_InitAtomMap(cx, map, &al);
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ return ok;
+ }
+
+ if (xdr->mode == JSXDR_ENCODE) {
+ JSAtomListElement ale;
+
+ for (i = 0; i < map->length; i++) {
+ ALE_SET_ATOM(&ale, map->vector[i]);
+ ALE_SET_INDEX(&ale, i);
+ if (!XDRAtomListElement(xdr, &ale))
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
+{
+ JSContext *cx;
+ JSScript *script, *newscript;
+ uint32 length, lineno, depth, magic, nsrcnotes, ntrynotes;
+ uint32 prologLength, version;
+ JSBool filenameWasSaved;
+ jssrcnote *notes, *sn;
+
+ cx = xdr->cx;
+ script = *scriptp;
+ nsrcnotes = ntrynotes = 0;
+ filenameWasSaved = JS_FALSE;
+ notes = NULL;
+
+ /*
+ * Encode prologLength and version after script->length (_2 or greater),
+ * but decode both new (>= _2) and old, prolog&version-free (_1) scripts.
+ * Version _3 supports principals serialization. Version _4 reorders the
+ * nsrcnotes and ntrynotes fields to come before everything except magic,
+ * length, prologLength, and version, so that srcnote and trynote storage
+ * can be allocated as part of the JSScript (along with bytecode storage).
+ */
+ if (xdr->mode == JSXDR_ENCODE)
+ magic = JSXDR_MAGIC_SCRIPT_CURRENT;
+ if (!JS_XDRUint32(xdr, &magic))
+ return JS_FALSE;
+ if (magic != JSXDR_MAGIC_SCRIPT_4 &&
+ magic != JSXDR_MAGIC_SCRIPT_3 &&
+ magic != JSXDR_MAGIC_SCRIPT_2 &&
+ magic != JSXDR_MAGIC_SCRIPT_1) {
+ if (!hasMagic) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_SCRIPT_MAGIC);
+ return JS_FALSE;
+ }
+ *hasMagic = JS_FALSE;
+ return JS_TRUE;
+ }
+ if (hasMagic)
+ *hasMagic = JS_TRUE;
+
+ if (xdr->mode == JSXDR_ENCODE) {
+ length = script->length;
+ prologLength = PTRDIFF(script->main, script->code, jsbytecode);
+ version = (int32)script->version;
+ lineno = (uint32)script->lineno;
+ depth = (uint32)script->depth;
+
+ /* Count the srcnotes, keeping notes pointing at the first one. */
+ notes = SCRIPT_NOTES(script);
+ for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
+ continue;
+ nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
+ nsrcnotes++; /* room for the terminator */
+
+ /* Count the trynotes. */
+ if (script->trynotes) {
+ while (script->trynotes[ntrynotes].catchStart)
+ ntrynotes++;
+ ntrynotes++; /* room for the end marker */
+ }
+ }
+
+ if (!JS_XDRUint32(xdr, &length))
+ return JS_FALSE;
+ if (magic >= JSXDR_MAGIC_SCRIPT_2) {
+ if (!JS_XDRUint32(xdr, &prologLength))
+ return JS_FALSE;
+ if (!JS_XDRUint32(xdr, &version))
+ return JS_FALSE;
+
+ /* To fuse allocations, we need srcnote and trynote counts early. */
+ if (magic >= JSXDR_MAGIC_SCRIPT_4) {
+ if (!JS_XDRUint32(xdr, &nsrcnotes))
+ return JS_FALSE;
+ if (!JS_XDRUint32(xdr, &ntrynotes))
+ return JS_FALSE;
+ }
+ }
+
+ if (xdr->mode == JSXDR_DECODE) {
+ script = js_NewScript(cx, length, nsrcnotes, ntrynotes);
+ if (!script)
+ return JS_FALSE;
+ if (magic >= JSXDR_MAGIC_SCRIPT_2) {
+ script->main += prologLength;
+ script->version = (JSVersion) version;
+
+ /* If we know nsrcnotes, we allocated space for notes in script. */
+ if (magic >= JSXDR_MAGIC_SCRIPT_4)
+ notes = SCRIPT_NOTES(script);
+ }
+ *scriptp = script;
+ }
+
+ /*
+ * Control hereafter must goto error on failure, in order for the DECODE
+ * case to destroy script and conditionally free notes, which if non-null
+ * in the (DECODE and version < _4) case must point at a temporary vector
+ * allocated just below.
+ */
+ if (!JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode)) ||
+ !XDRAtomMap(xdr, &script->atomMap)) {
+ goto error;
+ }
+
+ if (magic < JSXDR_MAGIC_SCRIPT_4) {
+ if (!JS_XDRUint32(xdr, &nsrcnotes))
+ goto error;
+ if (xdr->mode == JSXDR_DECODE) {
+ notes = (jssrcnote *) JS_malloc(cx, nsrcnotes * sizeof(jssrcnote));
+ if (!notes)
+ goto error;
+ }
+ }
+
+ if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
+ !JS_XDRCStringOrNull(xdr, (char **)&script->filename) ||
+ !JS_XDRUint32(xdr, &lineno) ||
+ !JS_XDRUint32(xdr, &depth) ||
+ (magic < JSXDR_MAGIC_SCRIPT_4 && !JS_XDRUint32(xdr, &ntrynotes))) {
+ goto error;
+ }
+
+ /* Script principals transcoding support comes with versions >= _3. */
+ if (magic >= JSXDR_MAGIC_SCRIPT_3) {
+ JSPrincipals *principals;
+ uint32 encodeable;
+
+ if (xdr->mode == JSXDR_ENCODE) {
+ principals = script->principals;
+ encodeable = (cx->runtime->principalsTranscoder != NULL);
+ if (!JS_XDRUint32(xdr, &encodeable))
+ goto error;
+ if (encodeable &&
+ !cx->runtime->principalsTranscoder(xdr, &principals)) {
+ goto error;
+ }
+ } else {
+ if (!JS_XDRUint32(xdr, &encodeable))
+ goto error;
+ if (encodeable) {
+ if (!cx->runtime->principalsTranscoder) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_DECODE_PRINCIPALS);
+ goto error;
+ }
+ if (!cx->runtime->principalsTranscoder(xdr, &principals))
+ goto error;
+ script->principals = principals;
+ }
+ }
+ }
+
+ if (xdr->mode == JSXDR_DECODE) {
+ const char *filename = script->filename;
+ if (filename) {
+ filename = js_SaveScriptFilename(cx, filename);
+ if (!filename)
+ goto error;
+ JS_free(cx, (void *) script->filename);
+ script->filename = filename;
+ filenameWasSaved = JS_TRUE;
+ }
+ script->lineno = (uintN)lineno;
+ script->depth = (uintN)depth;
+
+ if (magic < JSXDR_MAGIC_SCRIPT_4) {
+ /*
+ * Argh, we have to reallocate script, copy notes into the extra
+ * space after the bytecodes, and free the temporary notes vector.
+ * First, add enough slop to nsrcnotes so we can align the address
+ * after the srcnotes of the first trynote.
+ */
+ uint32 osrcnotes = nsrcnotes;
+
+ if (ntrynotes)
+ nsrcnotes += JSTRYNOTE_ALIGNMASK;
+ newscript = (JSScript *) JS_realloc(cx, script,
+ sizeof(JSScript) +
+ length * sizeof(jsbytecode) +
+ nsrcnotes * sizeof(jssrcnote) +
+ ntrynotes * sizeof(JSTryNote));
+ if (!newscript)
+ goto error;
+
+ *scriptp = script = newscript;
+ script->code = (jsbytecode *)(script + 1);
+ script->main = script->code + prologLength;
+ memcpy(script->code + length, notes, osrcnotes * sizeof(jssrcnote));
+ JS_free(cx, (void *) notes);
+ notes = NULL;
+ if (ntrynotes) {
+ script->trynotes = (JSTryNote *)
+ ((jsword)(SCRIPT_NOTES(script) + nsrcnotes) &
+ ~(jsword)JSTRYNOTE_ALIGNMASK);
+ }
+ }
+ }
+
+ while (ntrynotes) {
+ JSTryNote *tn = &script->trynotes[--ntrynotes];
+ uint32 start = (uint32) tn->start,
+ catchLength = (uint32) tn->length,
+ catchStart = (uint32) tn->catchStart;
+
+ if (!JS_XDRUint32(xdr, &start) ||
+ !JS_XDRUint32(xdr, &catchLength) ||
+ !JS_XDRUint32(xdr, &catchStart)) {
+ goto error;
+ }
+ tn->start = (ptrdiff_t) start;
+ tn->length = (ptrdiff_t) catchLength;
+ tn->catchStart = (ptrdiff_t) catchStart;
+ }
+ return JS_TRUE;
+
+ error:
+ if (xdr->mode == JSXDR_DECODE) {
+ if (script->filename && !filenameWasSaved) {
+ JS_free(cx, (void *) script->filename);
+ script->filename = NULL;
+ }
+ if (notes && magic < JSXDR_MAGIC_SCRIPT_4)
+ JS_free(cx, (void *) notes);
+ js_DestroyScript(cx, script);
+ *scriptp = NULL;
+ }
+ return JS_FALSE;
+}
+
+#if JS_HAS_XDR_FREEZE_THAW
+/*
+ * These cannot be exposed to web content, and chrome does not need them, so
+ * we take them out of the Mozilla client altogether. Fortunately, there is
+ * no way to serialize a native function (see fun_xdrObject in jsfun.c).
+ */
+
+static JSBool
+script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXDRState *xdr;
+ JSScript *script;
+ JSBool ok, hasMagic;
+ uint32 len;
+ void *buf;
+ JSString *str;
+
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
+ return JS_FALSE;
+ script = (JSScript *) JS_GetPrivate(cx, obj);
+ if (!script)
+ return JS_TRUE;
+
+ /* create new XDR */
+ xdr = JS_XDRNewMem(cx, JSXDR_ENCODE);
+ if (!xdr)
+ return JS_FALSE;
+
+ /* write */
+ ok = js_XDRScript(xdr, &script, &hasMagic);
+ if (!ok)
+ goto out;
+ if (!hasMagic) {
+ *rval = JSVAL_VOID;
+ goto out;
+ }
+
+ buf = JS_XDRMemGetData(xdr, &len);
+ if (!buf) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ JS_ASSERT((jsword)buf % sizeof(jschar) == 0);
+ len /= sizeof(jschar);
+ str = JS_NewUCStringCopyN(cx, (jschar *)buf, len);
+ if (!str) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+#if IS_BIG_ENDIAN
+ {
+ jschar *chars;
+ uint32 i;
+
+ /* Swap bytes in Unichars to keep frozen strings machine-independent. */
+ chars = JS_GetStringChars(str);
+ for (i = 0; i < len; i++)
+ chars[i] = JSXDR_SWAB16(chars[i]);
+ }
+#endif
+ *rval = STRING_TO_JSVAL(str);
+
+out:
+ JS_XDRDestroy(xdr);
+ return ok;
+}
+
+static JSBool
+script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXDRState *xdr;
+ JSString *str;
+ void *buf;
+ uint32 len;
+ JSScript *script, *oldscript;
+ JSBool ok, hasMagic;
+
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
+ return JS_FALSE;
+
+ if (argc == 0)
+ return JS_TRUE;
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+
+ /* create new XDR */
+ xdr = JS_XDRNewMem(cx, JSXDR_DECODE);
+ if (!xdr)
+ return JS_FALSE;
+
+ buf = JS_GetStringChars(str);
+ len = JS_GetStringLength(str);
+#if IS_BIG_ENDIAN
+ {
+ jschar *from, *to;
+ uint32 i;
+
+ /* Swap bytes in Unichars to keep frozen strings machine-independent. */
+ from = (jschar *)buf;
+ to = (jschar *) JS_malloc(cx, len * sizeof(jschar));
+ if (!to) {
+ JS_XDRDestroy(xdr);
+ return JS_FALSE;
+ }
+ for (i = 0; i < len; i++)
+ to[i] = JSXDR_SWAB16(from[i]);
+ buf = (char *)to;
+ }
+#endif
+ len *= sizeof(jschar);
+ JS_XDRMemSetData(xdr, buf, len);
+
+ /* XXXbe should magic mismatch be error, or false return value? */
+ ok = js_XDRScript(xdr, &script, &hasMagic);
+ if (!ok)
+ goto out;
+ if (!hasMagic) {
+ *rval = JSVAL_FALSE;
+ goto out;
+ }
+
+ /* Swap script for obj's old script, if any. */
+ oldscript = (JSScript *) JS_GetPrivate(cx, obj);
+ ok = JS_SetPrivate(cx, obj, script);
+ if (!ok) {
+ JS_free(cx, script);
+ goto out;
+ }
+ if (oldscript)
+ js_DestroyScript(cx, oldscript);
+
+ script->object = obj;
+ js_CallNewScriptHook(cx, script, NULL);
+
+out:
+ /*
+ * We reset the buffer to be NULL so that it doesn't free the chars
+ * memory owned by str (argv[0]).
+ */
+ JS_XDRMemSetData(xdr, NULL, 0);
+ JS_XDRDestroy(xdr);
+#if IS_BIG_ENDIAN
+ JS_free(cx, buf);
+#endif
+ *rval = JSVAL_TRUE;
+ return ok;
+}
+
+static const char js_thaw_str[] = "thaw";
+
+#endif /* JS_HAS_XDR_FREEZE_THAW */
+#endif /* JS_HAS_XDR */
+
+static JSFunctionSpec script_methods[] = {
+#if JS_HAS_TOSOURCE
+ {js_toSource_str, script_toSource, 0,0,0},
+#endif
+ {js_toString_str, script_toString, 0,0,0},
+ {"compile", script_compile, 2,0,0},
+ {"exec", script_exec, 1,0,0},
+#if JS_HAS_XDR_FREEZE_THAW
+ {"freeze", script_freeze, 0,0,0},
+ {js_thaw_str, script_thaw, 1,0,0},
+#endif /* JS_HAS_XDR_FREEZE_THAW */
+ {0,0,0,0,0}
+};
+
+#endif /* JS_HAS_SCRIPT_OBJECT */
+
+static void
+script_finalize(JSContext *cx, JSObject *obj)
+{
+ JSScript *script;
+
+ script = (JSScript *) JS_GetPrivate(cx, obj);
+ if (script)
+ js_DestroyScript(cx, script);
+}
+
+static JSBool
+script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+#if JS_HAS_SCRIPT_OBJECT
+ return script_exec(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
+#else
+ return JS_FALSE;
+#endif
+}
+
+static uint32
+script_mark(JSContext *cx, JSObject *obj, void *arg)
+{
+ JSScript *script;
+
+ script = (JSScript *) JS_GetPrivate(cx, obj);
+ if (script)
+ js_MarkScript(cx, script, arg);
+ return 0;
+}
+
+JS_FRIEND_DATA(JSClass) js_ScriptClass = {
+ js_Script_str,
+ JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize,
+ NULL, NULL, script_call, NULL,/*XXXbe xdr*/
+ NULL, NULL, script_mark, 0
+};
+
+#if JS_HAS_SCRIPT_OBJECT
+
+static JSBool
+Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ /* If not constructing, replace obj with a new Script object. */
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ }
+ return script_compile(cx, obj, argc, argv, rval);
+}
+
+#if JS_HAS_XDR_FREEZE_THAW
+
+static JSBool
+script_static_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ if (!script_thaw(cx, obj, argc, argv, rval))
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+static JSFunctionSpec script_static_methods[] = {
+ {js_thaw_str, script_static_thaw, 1,0,0},
+ {0,0,0,0,0}
+};
+
+#else /* !JS_HAS_XDR_FREEZE_THAW */
+
+#define script_static_methods NULL
+
+#endif /* !JS_HAS_XDR_FREEZE_THAW */
+
+JSObject *
+js_InitScriptClass(JSContext *cx, JSObject *obj)
+{
+ return JS_InitClass(cx, obj, NULL, &js_ScriptClass, Script, 1,
+ NULL, script_methods, NULL, script_static_methods);
+}
+
+#endif /* JS_HAS_SCRIPT_OBJECT */
+
+/*
+ * Shared script filename management.
+ */
+static JSHashTable *script_filename_table;
+#ifdef JS_THREADSAFE
+static JSLock *script_filename_table_lock;
+#endif
+
+JS_STATIC_DLL_CALLBACK(int)
+js_compare_strings(const void *k1, const void *k2)
+{
+ return strcmp(k1, k2) == 0;
+}
+
+/* Shared with jsatom.c to save code space. */
+extern void * JS_DLL_CALLBACK
+js_alloc_table_space(void *priv, size_t size);
+
+extern void JS_DLL_CALLBACK
+js_free_table_space(void *priv, void *item);
+
+/* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */
+typedef struct ScriptFilenameEntry {
+ JSHashEntry *next; /* hash chain linkage */
+ JSHashNumber keyHash; /* key hash function result */
+ const void *key; /* ptr to filename, below */
+ JSPackedBool mark; /* mark flag, for GC */
+ char filename[3]; /* two or more bytes, NUL-terminated */
+} ScriptFilenameEntry;
+
+JS_STATIC_DLL_CALLBACK(JSHashEntry *)
+js_alloc_entry(void *priv, const void *key)
+{
+ size_t nbytes = offsetof(ScriptFilenameEntry, filename) + strlen(key) + 1;
+
+ return (JSHashEntry *) malloc(JS_MAX(nbytes, sizeof(JSHashEntry)));
+}
+
+JS_STATIC_DLL_CALLBACK(void)
+js_free_entry(void *priv, JSHashEntry *he, uintN flag)
+{
+ if (flag != HT_FREE_ENTRY)
+ return;
+ free(he);
+}
+
+static JSHashAllocOps table_alloc_ops = {
+ js_alloc_table_space, js_free_table_space,
+ js_alloc_entry, js_free_entry
+};
+
+JSBool
+js_InitScriptGlobals()
+{
+#ifdef JS_THREADSAFE
+ /* Must come through here once in primordial thread to init safely! */
+ if (!script_filename_table_lock) {
+ script_filename_table_lock = JS_NEW_LOCK();
+ if (!script_filename_table_lock)
+ return JS_FALSE;
+ }
+#endif
+ if (!script_filename_table) {
+ JS_ACQUIRE_LOCK(script_filename_table_lock);
+ if (!script_filename_table) {
+ script_filename_table =
+ JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL,
+ &table_alloc_ops, NULL);
+ }
+ JS_RELEASE_LOCK(script_filename_table_lock);
+ if (!script_filename_table)
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+void
+js_FreeScriptGlobals()
+{
+ if (script_filename_table) {
+ JS_HashTableDestroy(script_filename_table);
+ script_filename_table = NULL;
+ }
+#ifdef JS_THREADSAFE
+ if (script_filename_table_lock) {
+ JS_DESTROY_LOCK(script_filename_table_lock);
+ script_filename_table_lock = NULL;
+ }
+#endif
+}
+
+#ifdef DEBUG_brendan
+size_t sft_savings = 0;
+#endif
+
+const char *
+js_SaveScriptFilename(JSContext *cx, const char *filename)
+{
+ JSHashTable *table;
+ JSHashNumber hash;
+ JSHashEntry **hep;
+ ScriptFilenameEntry *sfe;
+
+ JS_ACQUIRE_LOCK(script_filename_table_lock);
+ table = script_filename_table;
+ hash = JS_HashString(filename);
+ hep = JS_HashTableRawLookup(table, hash, filename);
+ sfe = (ScriptFilenameEntry *) *hep;
+#ifdef DEBUG_brendan
+ if (sfe)
+ sft_savings += strlen(sfe->filename);
+#endif
+ if (!sfe) {
+ sfe = (ScriptFilenameEntry *)
+ JS_HashTableRawAdd(table, hep, hash, filename, NULL);
+ if (sfe) {
+ sfe->key = strcpy(sfe->filename, filename);
+ JS_ASSERT(!sfe->mark);
+ }
+ }
+ JS_RELEASE_LOCK(script_filename_table_lock);
+ if (!sfe) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ return sfe->filename;
+}
+
+void
+js_MarkScriptFilename(const char *filename)
+{
+ ScriptFilenameEntry *sfe;
+
+ /*
+ * Back up from filename by its offset within its hash table entry.
+ * The sfe->key member, redundant given sfe->filename but required by
+ * the old jshash.c code, here gives us a useful sanity check. This
+ * assertion will very likely botch if someone tries to mark a string
+ * that wasn't allocated as an sfe->filename.
+ */
+ sfe = (ScriptFilenameEntry *)
+ (filename - offsetof(ScriptFilenameEntry, filename));
+ JS_ASSERT(sfe->key == sfe->filename);
+ sfe->mark = JS_TRUE;
+}
+
+JS_STATIC_DLL_CALLBACK(intN)
+js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg)
+{
+ ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
+
+ if (!sfe->mark)
+ return HT_ENUMERATE_REMOVE;
+ sfe->mark = JS_FALSE;
+ return HT_ENUMERATE_NEXT;
+}
+
+void
+js_SweepScriptFilenames(JSRuntime *rt)
+{
+ JS_HashTableEnumerateEntries(script_filename_table,
+ js_script_filename_sweeper,
+ rt);
+#ifdef DEBUG_brendan
+ printf("script filename table savings so far: %u\n", sft_savings);
+#endif
+}
+
+JSScript *
+js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 ntrynotes)
+{
+ JSScript *script;
+
+ /* Round up source note count to align script->trynotes for its type. */
+ if (ntrynotes)
+ nsrcnotes += JSTRYNOTE_ALIGNMASK;
+ script = (JSScript *) JS_malloc(cx,
+ sizeof(JSScript) +
+ length * sizeof(jsbytecode) +
+ nsrcnotes * sizeof(jssrcnote) +
+ ntrynotes * sizeof(JSTryNote));
+ if (!script)
+ return NULL;
+ memset(script, 0, sizeof(JSScript));
+ script->code = script->main = (jsbytecode *)(script + 1);
+ script->length = length;
+ script->version = cx->version;
+ if (ntrynotes) {
+ script->trynotes = (JSTryNote *)
+ ((jsword)(SCRIPT_NOTES(script) + nsrcnotes) &
+ ~(jsword)JSTRYNOTE_ALIGNMASK);
+ }
+ return script;
+}
+
+JS_FRIEND_API(JSScript *)
+js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun)
+{
+ uint32 mainLength, prologLength, nsrcnotes, ntrynotes;
+ JSScript *script;
+ const char *filename;
+
+ mainLength = CG_OFFSET(cg);
+ prologLength = CG_PROLOG_OFFSET(cg);
+ CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
+ CG_COUNT_FINAL_TRYNOTES(cg, ntrynotes);
+ script = js_NewScript(cx, prologLength + mainLength, nsrcnotes, ntrynotes);
+ if (!script)
+ return NULL;
+
+ /* Now that we have script, error control flow must go to label bad. */
+ script->main += prologLength;
+ memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
+ memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
+ if (!js_InitAtomMap(cx, &script->atomMap, &cg->atomList))
+ goto bad;
+
+ filename = cg->filename;
+ if (filename) {
+ script->filename = js_SaveScriptFilename(cx, filename);
+ if (!script->filename)
+ goto bad;
+ }
+ script->lineno = cg->firstLine;
+ script->depth = cg->maxStackDepth;
+ if (cg->principals) {
+ script->principals = cg->principals;
+ JSPRINCIPALS_HOLD(cx, script->principals);
+ }
+
+ if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script)))
+ goto bad;
+ if (script->trynotes)
+ js_FinishTakingTryNotes(cx, cg, script->trynotes);
+
+ /* Tell the debugger about this compiled script. */
+ js_CallNewScriptHook(cx, script, fun);
+ return script;
+
+bad:
+ js_DestroyScript(cx, script);
+ return NULL;
+}
+
+JS_FRIEND_API(void)
+js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
+{
+ JSRuntime *rt;
+ JSNewScriptHook hook;
+
+ rt = cx->runtime;
+ hook = rt->newScriptHook;
+ if (hook) {
+ /*
+ * We use a dummy stack frame to protect the script from a GC caused
+ * by debugger-hook execution.
+ *
+ * XXX We really need a way to manage local roots and such more
+ * XXX automatically, at which point we can remove this one-off hack
+ * XXX and others within the engine. See bug 40757 for discussion.
+ */
+ JSStackFrame dummy;
+
+ memset(&dummy, 0, sizeof dummy);
+ dummy.down = cx->fp;
+ dummy.script = script;
+ cx->fp = &dummy;
+
+ hook(cx, script->filename, script->lineno, script, fun,
+ rt->newScriptHookData);
+
+ cx->fp = dummy.down;
+ }
+}
+
+void
+js_DestroyScript(JSContext *cx, JSScript *script)
+{
+ JSRuntime *rt;
+ JSDestroyScriptHook hook;
+
+ rt = cx->runtime;
+ hook = rt->destroyScriptHook;
+ if (hook)
+ hook(cx, script, rt->destroyScriptHookData);
+
+ JS_ClearScriptTraps(cx, script);
+ js_FreeAtomMap(cx, &script->atomMap);
+ if (script->principals)
+ JSPRINCIPALS_DROP(cx, script->principals);
+ JS_free(cx, script);
+}
+
+void
+js_MarkScript(JSContext *cx, JSScript *script, void *arg)
+{
+ JSAtomMap *map;
+ uintN i, length;
+ JSAtom **vector;
+
+ map = &script->atomMap;
+ length = map->length;
+ vector = map->vector;
+ for (i = 0; i < length; i++)
+ GC_MARK_ATOM(cx, vector[i], arg);
+
+ if (script->filename)
+ js_MarkScriptFilename(script->filename);
+}
+
+jssrcnote *
+js_GetSrcNote(JSScript *script, jsbytecode *pc)
+{
+ jssrcnote *sn;
+ ptrdiff_t offset, target;
+
+ target = PTRDIFF(pc, script->code, jsbytecode);
+ if ((uint32)target >= script->length)
+ return NULL;
+ offset = 0;
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
+ offset += SN_DELTA(sn);
+ if (offset == target && SN_IS_GETTABLE(sn))
+ return sn;
+ }
+ return NULL;
+}
+
+uintN
+js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
+{
+ JSAtom *atom;
+ JSFunction *fun;
+ uintN lineno;
+ ptrdiff_t offset, target;
+ jssrcnote *sn;
+ JSSrcNoteType type;
+
+ /*
+ * Special case: function definition needs no line number note because
+ * the function's script contains its starting line number.
+ */
+ if (*pc == JSOP_DEFFUN) {
+ atom = GET_ATOM(cx, script, pc);
+ fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(atom));
+ return fun->script->lineno;
+ }
+
+ /*
+ * General case: walk through source notes accumulating their deltas,
+ * keeping track of line-number notes, until we pass the note for pc's
+ * offset within script->code.
+ */
+ lineno = script->lineno;
+ offset = 0;
+ target = PTRDIFF(pc, script->code, jsbytecode);
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
+ offset += SN_DELTA(sn);
+ type = (JSSrcNoteType) SN_TYPE(sn);
+ if (type == SRC_SETLINE) {
+ if (offset <= target)
+ lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
+ } else if (type == SRC_NEWLINE) {
+ if (offset <= target)
+ lineno++;
+ }
+ if (offset > target)
+ break;
+ }
+ return lineno;
+}
+
+jsbytecode *
+js_LineNumberToPC(JSScript *script, uintN target)
+{
+ ptrdiff_t offset;
+ uintN lineno;
+ jssrcnote *sn;
+ JSSrcNoteType type;
+
+ offset = 0;
+ lineno = script->lineno;
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
+ if (lineno >= target)
+ break;
+ offset += SN_DELTA(sn);
+ type = (JSSrcNoteType) SN_TYPE(sn);
+ if (type == SRC_SETLINE) {
+ lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
+ } else if (type == SRC_NEWLINE) {
+ lineno++;
+ }
+ }
+ return script->code + offset;
+}
+
+uintN
+js_GetScriptLineExtent(JSScript *script)
+{
+ uintN lineno;
+ jssrcnote *sn;
+ JSSrcNoteType type;
+
+ lineno = script->lineno;
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
+ type = (JSSrcNoteType) SN_TYPE(sn);
+ if (type == SRC_SETLINE) {
+ lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
+ } else if (type == SRC_NEWLINE) {
+ lineno++;
+ }
+ }
+ return 1 + lineno - script->lineno;
+}
diff --git a/src/dom/js/jsscript.h b/src/dom/js/jsscript.h
new file mode 100644
index 000000000..ffcc40de7
--- /dev/null
+++ b/src/dom/js/jsscript.h
@@ -0,0 +1,178 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsscript_h___
+#define jsscript_h___
+/*
+ * JS script descriptor.
+ */
+#include "jsatom.h"
+#include "jsprvtd.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * Exception handling runtime information.
+ *
+ * All fields except length are code offsets, relative to the beginning of
+ * the script. If script->trynotes is not null, it points to a vector of
+ * these structs terminated by one with catchStart == 0.
+ */
+struct JSTryNote {
+ ptrdiff_t start; /* start of try statement */
+ ptrdiff_t length; /* count of try statement bytecodes */
+ ptrdiff_t catchStart; /* start of catch block (0 if end) */
+};
+
+#define JSTRYNOTE_GRAIN sizeof(ptrdiff_t)
+#define JSTRYNOTE_ALIGNMASK (JSTRYNOTE_GRAIN - 1)
+
+struct JSScript {
+ jsbytecode *code; /* bytecodes and their immediate operands */
+ uint32 length; /* length of code vector */
+ jsbytecode *main; /* main entry point, after predef'ing prolog */
+ JSVersion version; /* JS version under which script was compiled */
+ JSAtomMap atomMap; /* maps immediate index to literal struct */
+ const char *filename; /* source filename or null */
+ uintN lineno; /* base line number of script */
+ uintN depth; /* maximum stack depth in slots */
+ JSTryNote *trynotes; /* exception table for this script */
+ JSPrincipals *principals; /* principals for this script */
+ JSObject *object; /* optional Script-class object wrapper */
+};
+
+/* No need to store script->notes now that it is allocated right after code. */
+#define SCRIPT_NOTES(script) ((jssrcnote*)((script)->code+(script)->length))
+
+#define SCRIPT_FIND_CATCH_START(script, pc, catchpc) \
+ JS_BEGIN_MACRO \
+ JSTryNote *tn_ = (script)->trynotes; \
+ jsbytecode *catchpc_ = NULL; \
+ if (tn_) { \
+ ptrdiff_t off_ = PTRDIFF(pc, (script)->main, jsbytecode); \
+ if (off_ >= 0) { \
+ while ((jsuword)(off_ - tn_->start) >= (jsuword)tn_->length) \
+ ++tn_; \
+ if (tn_->catchStart) \
+ catchpc_ = (script)->main + tn_->catchStart; \
+ } \
+ } \
+ catchpc = catchpc_; \
+ JS_END_MACRO
+
+extern JS_FRIEND_DATA(JSClass) js_ScriptClass;
+
+extern JSObject *
+js_InitScriptClass(JSContext *cx, JSObject *obj);
+
+extern JSBool
+js_InitScriptGlobals();
+
+extern void
+js_FreeScriptGlobals();
+
+extern const char *
+js_SaveScriptFilename(JSContext *cx, const char *filename);
+
+extern void
+js_MarkScriptFilename(const char *filename);
+
+extern void
+js_SweepScriptFilenames(JSRuntime *rt);
+
+/*
+ * Two successively less primitive ways to make a new JSScript. The first
+ * does *not* call a non-null cx->runtime->newScriptHook -- only the second,
+ * js_NewScriptFromCG, calls this optional debugger hook.
+ *
+ * The js_NewScript function can't know whether the script it creates belongs
+ * to a function, or is top-level or eval code, but the debugger wants access
+ * to the newly made script's function, if any -- so callers of js_NewScript
+ * are responsible for notifying the debugger after successfully creating any
+ * kind (function or other) of new JSScript.
+ */
+extern JSScript *
+js_NewScript(JSContext *cx, uint32 length, uint32 snlength, uint32 tnlength);
+
+extern JS_FRIEND_API(JSScript *)
+js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun);
+
+/*
+ * New-script-hook calling is factored from js_NewScriptFromCG so that it
+ * and callers of js_XDRScript can share this code. In the case of callers
+ * of js_XDRScript, the hook should be invoked only after successful decode
+ * of any owning function (the fun parameter) or script object (null fun).
+ */
+extern JS_FRIEND_API(void)
+js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
+
+extern void
+js_DestroyScript(JSContext *cx, JSScript *script);
+
+extern void
+js_MarkScript(JSContext *cx, JSScript *script, void *arg);
+
+extern jssrcnote *
+js_GetSrcNote(JSScript *script, jsbytecode *pc);
+
+/* XXX need cx to lock function objects declared by prolog bytecodes. */
+extern uintN
+js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
+
+extern jsbytecode *
+js_LineNumberToPC(JSScript *script, uintN lineno);
+
+extern uintN
+js_GetScriptLineExtent(JSScript *script);
+
+/*
+ * If magic is non-null, js_XDRScript succeeds on magic number mismatch but
+ * returns false in *magic; it reflects a match via a true *magic out param.
+ * If magic is null, js_XDRScript returns false on bad magic number errors,
+ * which it reports.
+ *
+ * NB: callers must call js_CallNewScriptHook after successful JSXDR_DECODE
+ * and subsequent set-up of owning function or script object, if any.
+ */
+extern JSBool
+js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic);
+
+JS_END_EXTERN_C
+
+#endif /* jsscript_h___ */
diff --git a/src/dom/js/jsshell.msg b/src/dom/js/jsshell.msg
new file mode 100644
index 000000000..4b811ac01
--- /dev/null
+++ b/src/dom/js/jsshell.msg
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ Error messages for JSShell. See js.msg for format.
+*/
+
+MSG_DEF(JSSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "<Error #0 is reserved>")
+MSG_DEF(JSSMSG_CANT_OPEN, 1, 2, JSEXN_NONE, "can't open {0}: {1}")
+MSG_DEF(JSSMSG_TRAP_USAGE, 2, 0, JSEXN_NONE, "usage: trap [fun] [pc] expr")
+MSG_DEF(JSSMSG_LINE2PC_USAGE, 3, 0, JSEXN_NONE, "usage: line2pc [fun] line")
+MSG_DEF(JSSMSG_FILE_SCRIPTS_ONLY, 4, 0, JSEXN_NONE, "only works on JS scripts read from files")
+MSG_DEF(JSSMSG_UNEXPECTED_EOF, 5, 1, JSEXN_NONE, "unexpected EOF in {0}")
+MSG_DEF(JSSMSG_DOEXP_USAGE, 6, 0, JSEXN_NONE, "usage: doexp obj id")
diff --git a/src/dom/js/jsstddef.h b/src/dom/js/jsstddef.h
new file mode 100644
index 000000000..0d87b0c0c
--- /dev/null
+++ b/src/dom/js/jsstddef.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * stddef inclusion here to first declare ptrdif as a signed long instead of a
+ * signed int.
+ */
+
+#ifdef _WINDOWS
+# ifndef XP_WIN
+# define XP_WIN
+# endif
+#if defined(_WIN32) || defined(WIN32)
+# ifndef XP_WIN32
+# define XP_WIN32
+# endif
+#else
+# ifndef XP_WIN16
+# define XP_WIN16
+# endif
+#endif
+#endif
+
+#ifdef XP_WIN16
+#ifndef _PTRDIFF_T_DEFINED
+typedef long ptrdiff_t;
+
+/*
+ * The Win16 compiler treats pointer differences as 16-bit signed values.
+ * This macro allows us to treat them as 17-bit signed values, stored in
+ * a 32-bit type.
+ */
+#define PTRDIFF(p1, p2, type) \
+ ((((unsigned long)(p1)) - ((unsigned long)(p2))) / sizeof(type))
+
+#define _PTRDIFF_T_DEFINED
+#endif /*_PTRDIFF_T_DEFINED*/
+#else /*WIN16*/
+
+#define PTRDIFF(p1, p2, type) \
+ ((p1) - (p2))
+
+#endif
+
+#include <stddef.h>
+
+
diff --git a/src/dom/js/jsstr.c b/src/dom/js/jsstr.c
new file mode 100644
index 000000000..e143ab8df
--- /dev/null
+++ b/src/dom/js/jsstr.c
@@ -0,0 +1,4502 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * JS string type implementation.
+ *
+ * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
+ * native methods store strings (possibly newborn) converted from their 'this'
+ * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
+ * conversions at their index (argv[0], argv[1]). This is a legitimate method
+ * of rooting things that might lose their newborn root due to subsequent GC
+ * allocations in the same native method.
+ */
+#include "jsstddef.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jshash.h" /* Added by JSIFY */
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsconfig.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsregexp.h"
+#include "jsstr.h"
+
+#if JS_HAS_REPLACE_LAMBDA
+#include "jsinterp.h"
+#endif
+
+#define JSSTRDEP_RECURSION_LIMIT 100
+
+size_t
+js_MinimizeDependentStrings(JSString *str, int level, JSString **basep)
+{
+ JSString *base;
+ size_t start, length;
+
+ JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
+ base = JSSTRDEP_BASE(str);
+ start = JSSTRDEP_START(str);
+ if (JSSTRING_IS_DEPENDENT(base)) {
+ if (level < JSSTRDEP_RECURSION_LIMIT) {
+ start += js_MinimizeDependentStrings(base, level + 1, &base);
+ } else {
+ do {
+ start += JSSTRDEP_START(base);
+ base = JSSTRDEP_BASE(base);
+ } while (JSSTRING_IS_DEPENDENT(base));
+ }
+ if (start == 0) {
+ JS_ASSERT(JSSTRING_IS_PREFIX(str));
+ JSPREFIX_SET_BASE(str, base);
+ } else if (start <= JSSTRDEP_START_MASK) {
+ length = JSSTRDEP_LENGTH(str);
+ JSSTRDEP_SET_START_AND_LENGTH(str, start, length);
+ JSSTRDEP_SET_BASE(str, base);
+ }
+ }
+ *basep = base;
+ return start;
+}
+
+jschar *
+js_GetDependentStringChars(JSString *str)
+{
+ size_t start;
+ JSString *base;
+
+ start = js_MinimizeDependentStrings(str, 0, &base);
+ JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
+ JS_ASSERT(start < base->length);
+ return base->chars + start;
+}
+
+jschar *
+js_GetStringChars(JSString *str)
+{
+ if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(NULL, str))
+ return NULL;
+
+ *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
+ return str->chars;
+}
+
+JSString *
+js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
+{
+ size_t rn, ln, lrdist, n;
+ jschar *rs, *ls, *s;
+ JSDependentString *ldep; /* non-null if left should become dependent */
+ JSString *str;
+
+ if (JSSTRING_IS_DEPENDENT(right)) {
+ rn = JSSTRDEP_LENGTH(right);
+ rs = JSSTRDEP_CHARS(right);
+ } else {
+ rn = right->length;
+ rs = right->chars;
+ }
+ if (rn == 0)
+ return left;
+
+ if (JSSTRING_IS_DEPENDENT(left) ||
+ !(*js_GetGCThingFlags(left) & GCF_MUTABLE)) {
+ /* We must copy if left does not own a buffer to realloc. */
+ ln = JSSTRING_LENGTH(left);
+ if (ln == 0)
+ return right;
+ ls = JSSTRING_CHARS(left);
+ s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar));
+ if (!s)
+ return NULL;
+ js_strncpy(s, ls, ln);
+ ldep = NULL;
+ } else {
+ /* We can realloc left's space and make it depend on our result. */
+ ln = left->length;
+ if (ln == 0)
+ return right;
+ ls = left->chars;
+ s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar));
+ if (!s)
+ return NULL;
+
+ /* Take care: right could depend on left! */
+ lrdist = (size_t)(rs - ls);
+ if (lrdist < ln)
+ rs = s + lrdist;
+ left->chars = ls = s;
+ ldep = JSSTRDEP(left);
+ }
+
+ js_strncpy(s + ln, rs, rn);
+ n = ln + rn;
+ s[n] = 0;
+ str = js_NewString(cx, s, n, GCF_MUTABLE);
+ if (!str) {
+ /* Out of memory: clean up any space we (re-)allocated. */
+ if (!ldep) {
+ JS_free(cx, s);
+ } else {
+ s = JS_realloc(cx, ls, (ln + 1) * sizeof(jschar));
+ if (s)
+ left->chars = s;
+ }
+ } else {
+ /* Morph left into a dependent prefix if we realloc'd its buffer. */
+ if (ldep) {
+ JSPREFIX_SET_LENGTH(ldep, ln);
+ JSPREFIX_SET_BASE(ldep, str);
+#ifdef DEBUG
+ {
+ JSRuntime *rt = cx->runtime;
+ JS_RUNTIME_METER(rt, liveDependentStrings);
+ JS_RUNTIME_METER(rt, totalDependentStrings);
+ JS_LOCK_RUNTIME_VOID(rt,
+ (rt->strdepLengthSum += (double)ln,
+ rt->strdepLengthSquaredSum += (double)ln * (double)ln));
+ }
+#endif
+ }
+ }
+
+ return str;
+}
+
+/*
+ * May be called with null cx by js_GetStringChars, above; and by the jslock.c
+ * MAKE_STRING_IMMUTABLE file-local macro.
+ */
+const jschar *
+js_UndependString(JSContext *cx, JSString *str)
+{
+ size_t n, size;
+ jschar *s;
+
+ if (JSSTRING_IS_DEPENDENT(str)) {
+ n = JSSTRDEP_LENGTH(str);
+ size = (n + 1) * sizeof(jschar);
+ s = (jschar *) (cx ? JS_malloc(cx, size) : malloc(size));
+ if (!s)
+ return NULL;
+
+ js_strncpy(s, JSSTRDEP_CHARS(str), n);
+ s[n] = 0;
+ str->length = n;
+ str->chars = s;
+
+#ifdef DEBUG
+ if (cx) {
+ JSRuntime *rt = cx->runtime;
+ JS_RUNTIME_UNMETER(rt, liveDependentStrings);
+ JS_RUNTIME_UNMETER(rt, totalDependentStrings);
+ JS_LOCK_RUNTIME_VOID(rt,
+ (rt->strdepLengthSum -= (double)n,
+ rt->strdepLengthSquaredSum -= (double)n * (double)n));
+ }
+#endif
+ }
+
+ return str->chars;
+}
+
+/*
+ * Forward declarations for URI encode/decode and helper routines
+ */
+static JSBool
+str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+static JSBool
+str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+static JSBool
+str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+static JSBool
+str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+static int
+OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char);
+
+static uint32
+Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
+
+/*
+ * Contributions from the String class to the set of methods defined for the
+ * global object. escape and unescape used to be defined in the Mocha library,
+ * but as ECMA decided to spec them, they've been moved to the core engine
+ * and made ECMA-compliant. (Incomplete escapes are interpreted as literal
+ * characters by unescape.)
+ */
+
+/*
+ * Stuff to emulate the old libmocha escape, which took a second argument
+ * giving the type of escape to perform. Retained for compatibility, and
+ * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
+ */
+
+#define URL_XALPHAS ((uint8) 1)
+#define URL_XPALPHAS ((uint8) 2)
+#define URL_PATH ((uint8) 4)
+
+static const uint8 urlCharType[256] =
+/* Bit 0 xalpha -- the alphas
+ * Bit 1 xpalpha -- as xalpha but
+ * converts spaces to plus and plus to %20
+ * Bit 2 ... path -- as xalphas but doesn't escape '/'
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
+ 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
+ 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
+ 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
+ 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
+ 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
+ 0, };
+
+/* This matches the ECMA escape set when mask is 7 (default.) */
+
+#define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
+
+/* See ECMA-262 15.1.2.4. */
+JSBool
+js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ size_t i, ni, length, newlength;
+ const jschar *chars;
+ jschar *newchars;
+ jschar ch;
+ jsint mask;
+ jsdouble d;
+ const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
+ if (argc > 1) {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+ if (!JSDOUBLE_IS_FINITE(d) ||
+ (mask = (jsint)d) != d ||
+ mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
+ {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_STRING_MASK, numBuf);
+ return JS_FALSE;
+ }
+ }
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str);
+
+ chars = JSSTRING_CHARS(str);
+ length = newlength = JSSTRING_LENGTH(str);
+
+ /* Take a first pass and see how big the result string will need to be. */
+ for (i = 0; i < length; i++) {
+ if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
+ continue;
+ if (ch < 256) {
+ if (mask == URL_XPALPHAS && ch == ' ')
+ continue; /* The character will be encoded as '+' */
+ newlength += 2; /* The character will be encoded as %XX */
+ } else {
+ newlength += 5; /* The character will be encoded as %uXXXX */
+ }
+ }
+
+ newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar));
+ if (!newchars)
+ return JS_FALSE;
+ for (i = 0, ni = 0; i < length; i++) {
+ if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
+ newchars[ni++] = ch;
+ } else if (ch < 256) {
+ if (mask == URL_XPALPHAS && ch == ' ') {
+ newchars[ni++] = '+'; /* convert spaces to pluses */
+ } else {
+ newchars[ni++] = '%';
+ newchars[ni++] = digits[ch >> 4];
+ newchars[ni++] = digits[ch & 0xF];
+ }
+ } else {
+ newchars[ni++] = '%';
+ newchars[ni++] = 'u';
+ newchars[ni++] = digits[ch >> 12];
+ newchars[ni++] = digits[(ch & 0xF00) >> 8];
+ newchars[ni++] = digits[(ch & 0xF0) >> 4];
+ newchars[ni++] = digits[ch & 0xF];
+ }
+ }
+ JS_ASSERT(ni == newlength);
+ newchars[newlength] = 0;
+
+ str = js_NewString(cx, newchars, newlength, 0);
+ if (!str) {
+ JS_free(cx, newchars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#undef IS_OK
+
+/* See ECMA-262 15.1.2.5 */
+static JSBool
+str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ size_t i, ni, length;
+ const jschar *chars;
+ jschar *newchars;
+ jschar ch;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str);
+
+ chars = JSSTRING_CHARS(str);
+ length = JSSTRING_LENGTH(str);
+
+ /* Don't bother allocating less space for the new string. */
+ newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
+ if (!newchars)
+ return JS_FALSE;
+ ni = i = 0;
+ while (i < length) {
+ ch = chars[i++];
+ if (ch == '%') {
+ if (i + 1 < length &&
+ JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
+ {
+ ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
+ i += 2;
+ } else if (i + 4 < length && chars[i] == 'u' &&
+ JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) &&
+ JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4]))
+ {
+ ch = (((((JS7_UNHEX(chars[i + 1]) << 4)
+ + JS7_UNHEX(chars[i + 2])) << 4)
+ + JS7_UNHEX(chars[i + 3])) << 4)
+ + JS7_UNHEX(chars[i + 4]);
+ i += 5;
+ }
+ }
+ newchars[ni++] = ch;
+ }
+ newchars[ni] = 0;
+
+ str = js_NewString(cx, newchars, ni, 0);
+ if (!str) {
+ JS_free(cx, newchars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+#if JS_HAS_UNEVAL
+static JSBool
+str_uneval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+
+ str = js_ValueToSource(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif
+
+const char js_escape_str[] = "escape";
+const char js_unescape_str[] = "unescape";
+#if JS_HAS_UNEVAL
+const char js_uneval_str[] = "uneval";
+#endif
+const char js_decodeURI_str[] = "decodeURI";
+const char js_encodeURI_str[] = "encodeURI";
+const char js_decodeURIComponent_str[] = "decodeURIComponent";
+const char js_encodeURIComponent_str[] = "encodeURIComponent";
+
+static JSFunctionSpec string_functions[] = {
+ {js_escape_str, js_str_escape, 1,0,0},
+ {js_unescape_str, str_unescape, 1,0,0},
+#if JS_HAS_UNEVAL
+ {js_uneval_str, str_uneval, 1,0,0},
+#endif
+ {js_decodeURI_str, str_decodeURI, 1,0,0},
+ {js_encodeURI_str, str_encodeURI, 1,0,0},
+ {js_decodeURIComponent_str, str_decodeURI_Component, 1,0,0},
+ {js_encodeURIComponent_str, str_encodeURI_Component, 1,0,0},
+
+ {0,0,0,0,0}
+};
+
+jschar js_empty_ucstr[] = {0};
+JSSubString js_EmptySubString = {0, js_empty_ucstr};
+
+enum string_tinyid {
+ STRING_LENGTH = -1
+};
+
+static JSPropertySpec string_props[] = {
+ {js_length_str, STRING_LENGTH,
+ JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, 0,0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSString *str;
+ jsint slot;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ slot = JSVAL_TO_INT(id);
+ if (slot == STRING_LENGTH)
+ *vp = INT_TO_JSVAL((jsint) JSSTRING_LENGTH(str));
+ return JS_TRUE;
+}
+
+#define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
+
+static JSBool
+str_enumerate(JSContext *cx, JSObject *obj)
+{
+ JSString *str, *str1;
+ size_t i, length;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ length = JSSTRING_LENGTH(str);
+ for (i = 0; i < length; i++) {
+ str1 = js_NewDependentString(cx, str, i, 1, 0);
+ if (!str1)
+ return JS_FALSE;
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(i),
+ STRING_TO_JSVAL(str1), NULL, NULL,
+ STRING_ELEMENT_ATTRS, NULL)) {
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+str_resolve(JSContext *cx, JSObject *obj, jsval id)
+{
+ JSString *str, *str1;
+ jsint slot;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ slot = JSVAL_TO_INT(id);
+ if ((size_t)slot < JSSTRING_LENGTH(str)) {
+ str1 = js_NewDependentString(cx, str, (size_t)slot, 1, 0);
+ if (!str1)
+ return JS_FALSE;
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(slot),
+ STRING_TO_JSVAL(str1), NULL, NULL,
+ STRING_ELEMENT_ATTRS, NULL)) {
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSClass string_class = {
+ js_String_str,
+ JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, str_getProperty, JS_PropertyStub,
+ str_enumerate, str_resolve, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+#if JS_HAS_TOSOURCE
+
+/*
+ * String.prototype.quote is generic (as are most string methods), unlike
+ * toSource, toString, and valueOf.
+ */
+static JSBool
+str_quote(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ str = js_QuoteString(cx, str, '"');
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+ JSString *str;
+ size_t i, j, k, n;
+ char buf[16];
+ jschar *s, *t;
+
+ if (!JS_InstanceOf(cx, obj, &string_class, argv))
+ return JS_FALSE;
+ v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ if (!JSVAL_IS_STRING(v))
+ return js_obj_toSource(cx, obj, argc, argv, rval);
+ str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
+ if (!str)
+ return JS_FALSE;
+ j = JS_snprintf(buf, sizeof buf, "(new %s(", string_class.name);
+ s = JSSTRING_CHARS(str);
+ k = JSSTRING_LENGTH(str);
+ n = j + k + 2;
+ t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
+ if (!t)
+ return JS_FALSE;
+ for (i = 0; i < j; i++)
+ t[i] = buf[i];
+ for (j = 0; j < k; i++, j++)
+ t[i] = s[j];
+ t[i++] = ')';
+ t[i++] = ')';
+ t[i] = 0;
+ str = js_NewString(cx, t, n, 0);
+ if (!str) {
+ JS_free(cx, t);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+#endif /* JS_HAS_TOSOURCE */
+
+static JSBool
+str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+
+ if (!JS_InstanceOf(cx, obj, &string_class, argv))
+ return JS_FALSE;
+ v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ if (!JSVAL_IS_STRING(v))
+ return js_obj_toString(cx, obj, argc, argv, rval);
+ *rval = v;
+ return JS_TRUE;
+}
+
+static JSBool
+str_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ if (!JS_InstanceOf(cx, obj, &string_class, argv))
+ return JS_FALSE;
+ *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ return JS_TRUE;
+}
+
+/*
+ * Java-like string native methods.
+ */
+static JSBool
+str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+ jsdouble d;
+ jsdouble length, begin, end;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ if (argc != 0) {
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ length = JSSTRING_LENGTH(str);
+ begin = js_DoubleToInteger(d);
+ if (begin < 0)
+ begin = 0;
+ else if (begin > length)
+ begin = length;
+
+ if (argc == 1) {
+ end = length;
+ } else {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+ end = js_DoubleToInteger(d);
+ if (end < 0)
+ end = 0;
+ else if (end > length)
+ end = length;
+ if (end < begin) {
+ if (cx->version != JSVERSION_1_2) {
+ /* XXX emulate old JDK1.0 java.lang.String.substring. */
+ jsdouble tmp = begin;
+ begin = end;
+ end = tmp;
+ } else {
+ end = begin;
+ }
+ }
+ }
+
+ str = js_NewDependentString(cx, str, (size_t)begin,
+ (size_t)(end - begin), 0);
+ if (!str)
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+ size_t i, n;
+ jschar *s, *news;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ n = JSSTRING_LENGTH(str);
+ news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
+ if (!news)
+ return JS_FALSE;
+ s = JSSTRING_CHARS(str);
+ for (i = 0; i < n; i++)
+ news[i] = JS_TOLOWER(s[i]);
+ news[n] = 0;
+ str = js_NewString(cx, news, n, 0);
+ if (!str) {
+ JS_free(cx, news);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+
+ /*
+ * Forcefully ignore the first (or any) argument and return toLowerCase(),
+ * ECMA has reserved that argument, presumably for defining the locale.
+ */
+ if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ return cx->localeCallbacks->localeToLowerCase(cx, str, rval);
+ }
+ return str_toLowerCase(cx, obj, 0, argv, rval);
+}
+
+static JSBool
+str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+ size_t i, n;
+ jschar *s, *news;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ n = JSSTRING_LENGTH(str);
+ news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
+ if (!news)
+ return JS_FALSE;
+ s = JSSTRING_CHARS(str);
+ for (i = 0; i < n; i++)
+ news[i] = JS_TOUPPER(s[i]);
+ news[n] = 0;
+ str = js_NewString(cx, news, n, 0);
+ if (!str) {
+ JS_free(cx, news);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+
+ /*
+ * Forcefully ignore the first (or any) argument and return toUpperCase(),
+ * ECMA has reserved that argument, presumbaly for defining the locale.
+ */
+ if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ return cx->localeCallbacks->localeToUpperCase(cx, str, rval);
+ }
+ return str_toUpperCase(cx, obj, 0, argv, rval);
+}
+
+static JSBool
+str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str, *thatStr;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ if (argc == 0) {
+ *rval = JSVAL_ZERO;
+ } else {
+ thatStr = js_ValueToString(cx, argv[0]);
+ if (!thatStr)
+ return JS_FALSE;
+ if (cx->localeCallbacks && cx->localeCallbacks->localeCompare)
+ return cx->localeCallbacks->localeCompare(cx, str, thatStr, rval);
+ *rval = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+str_charAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ jsdouble d;
+ size_t index;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ if (argc == 0) {
+ d = 0.0;
+ } else {
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ d = js_DoubleToInteger(d);
+ }
+
+ if (d < 0 || JSSTRING_LENGTH(str) <= d) {
+ *rval = JS_GetEmptyStringValue(cx);
+ } else {
+ index = (size_t)d;
+ str = js_NewDependentString(cx, str, index, 1, 0);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+str_charCodeAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+ jsdouble d;
+ size_t index;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ if (argc == 0) {
+ d = 0.0;
+ } else {
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ d = js_DoubleToInteger(d);
+ }
+
+ if (d < 0 || JSSTRING_LENGTH(str) <= d) {
+ *rval = JS_GetNaNValue(cx);
+ } else {
+ index = (size_t)d;
+ *rval = INT_TO_JSVAL((jsint) JSSTRING_CHARS(str)[index]);
+ }
+ return JS_TRUE;
+}
+
+jsint
+js_BoyerMooreHorspool(const jschar *text, jsint textlen,
+ const jschar *pat, jsint patlen,
+ jsint start)
+{
+ jsint i, j, k, m;
+ uint8 skip[BMH_CHARSET_SIZE];
+ jschar c;
+
+ JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
+ for (i = 0; i < BMH_CHARSET_SIZE; i++)
+ skip[i] = (uint8)patlen;
+ m = patlen - 1;
+ for (i = 0; i < m; i++) {
+ c = pat[i];
+ if (c >= BMH_CHARSET_SIZE)
+ return BMH_BAD_PATTERN;
+ skip[c] = (uint8)(m - i);
+ }
+ for (k = start + m;
+ k < textlen;
+ k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
+ for (i = k, j = m; ; i--, j--) {
+ if (j < 0)
+ return i + 1;
+ if (text[i] != pat[j])
+ break;
+ }
+ }
+ return -1;
+}
+
+static JSBool
+str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str, *str2;
+ jsint i, j, index, textlen, patlen;
+ const jschar *text, *pat;
+ jsdouble d;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+ text = JSSTRING_CHARS(str);
+ textlen = (jsint) JSSTRING_LENGTH(str);
+
+ str2 = js_ValueToString(cx, argv[0]);
+ if (!str2)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str2);
+ pat = JSSTRING_CHARS(str2);
+ patlen = (jsint) JSSTRING_LENGTH(str2);
+
+ if (argc > 1) {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+ d = js_DoubleToInteger(d);
+ if (d < 0)
+ i = 0;
+ else if (d > textlen)
+ i = textlen;
+ else
+ i = (jsint)d;
+ } else {
+ i = 0;
+ }
+ if (patlen == 0) {
+ *rval = INT_TO_JSVAL(i);
+ return JS_TRUE;
+ }
+
+ /* XXX tune the BMH threshold (512) */
+ if ((jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2 && textlen >= 512) {
+ index = js_BoyerMooreHorspool(text, textlen, pat, patlen, i);
+ if (index != BMH_BAD_PATTERN)
+ goto out;
+ }
+
+ index = -1;
+ j = 0;
+ while (i + j < textlen) {
+ if (text[i + j] == pat[j]) {
+ if (++j == patlen) {
+ index = i;
+ break;
+ }
+ } else {
+ i++;
+ j = 0;
+ }
+ }
+
+out:
+ *rval = INT_TO_JSVAL(index);
+ return JS_TRUE;
+}
+
+static JSBool
+str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str, *str2;
+ const jschar *text, *pat;
+ jsint i, j, textlen, patlen;
+ jsdouble d;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+ text = JSSTRING_CHARS(str);
+ textlen = (jsint) JSSTRING_LENGTH(str);
+
+ str2 = js_ValueToString(cx, argv[0]);
+ if (!str2)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str2);
+ pat = JSSTRING_CHARS(str2);
+ patlen = (jsint) JSSTRING_LENGTH(str2);
+
+ if (argc > 1) {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+ if (JSDOUBLE_IS_NaN(d)) {
+ i = textlen;
+ } else {
+ d = js_DoubleToInteger(d);
+ if (d < 0)
+ i = 0;
+ else if (d > textlen - patlen)
+ i = textlen - patlen;
+ else
+ i = (jsint)d;
+ }
+ } else {
+ i = textlen;
+ }
+
+ if (patlen == 0) {
+ *rval = INT_TO_JSVAL(i);
+ return JS_TRUE;
+ }
+
+ j = 0;
+ while (i >= 0) {
+ /* Don't assume that text is NUL-terminated: it could be dependent. */
+ if (i + j < textlen && text[i + j] == pat[j]) {
+ if (++j == patlen)
+ break;
+ } else {
+ i--;
+ j = 0;
+ }
+ }
+ *rval = INT_TO_JSVAL(i);
+ return JS_TRUE;
+}
+
+/*
+ * Perl-inspired string functions.
+ */
+#if JS_HAS_REGEXPS
+typedef struct GlobData {
+ uintN flags; /* inout: mode and flag bits, see below */
+ uintN optarg; /* in: index of optional flags argument */
+ JSString *str; /* out: 'this' parameter object as string */
+ JSRegExp *regexp; /* out: regexp parameter object private data */
+} GlobData;
+
+/*
+ * Mode and flag bit definitions for match_or_replace's GlobData.flags field.
+ */
+#define MODE_MATCH 0x00 /* in: return match array on success */
+#define MODE_REPLACE 0x01 /* in: match and replace */
+#define MODE_SEARCH 0x02 /* in: search only, return match index or -1 */
+#define GET_MODE(f) ((f) & 0x03)
+#define FORCE_FLAT 0x04 /* in: force flat (non-regexp) string match */
+#define KEEP_REGEXP 0x08 /* inout: keep GlobData.regexp alive for caller
+ of match_or_replace; if set on input
+ but clear on output, regexp ownership
+ does not pass to caller */
+#define GLOBAL_REGEXP 0x10 /* out: regexp had the 'g' flag */
+
+static JSBool
+match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ JSBool (*glob)(JSContext *cx, jsint count, GlobData *data),
+ GlobData *data, jsval *rval)
+{
+ JSString *str, *src, *opt;
+ JSObject *reobj;
+ JSRegExp *re;
+ size_t index, length;
+ JSBool ok, test;
+ jsint count;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+ data->str = str;
+
+ if (JSVAL_IS_REGEXP(cx, argv[0])) {
+ reobj = JSVAL_TO_OBJECT(argv[0]);
+ re = (JSRegExp *) JS_GetPrivate(cx, reobj);
+ } else {
+ src = js_ValueToString(cx, argv[0]);
+ if (!src)
+ return JS_FALSE;
+ if (data->optarg < argc) {
+ argv[0] = STRING_TO_JSVAL(src);
+ opt = js_ValueToString(cx, argv[data->optarg]);
+ if (!opt)
+ return JS_FALSE;
+ } else {
+ opt = NULL;
+ }
+ re = js_NewRegExpOpt(cx, NULL, src, opt,
+ (data->flags & FORCE_FLAT) != 0);
+ if (!re)
+ return JS_FALSE;
+ reobj = NULL;
+ }
+ data->regexp = re;
+
+ if (re->flags & JSREG_GLOB)
+ data->flags |= GLOBAL_REGEXP;
+ index = 0;
+ if (GET_MODE(data->flags) == MODE_SEARCH) {
+ ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
+ if (ok) {
+ *rval = (*rval == JSVAL_TRUE)
+ ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length)
+ : INT_TO_JSVAL(-1);
+ }
+ } else if (data->flags & GLOBAL_REGEXP) {
+ if (reobj) {
+ /* Set the lastIndex property's reserved slot to 0. */
+ ok = js_SetLastIndex(cx, reobj, 0);
+ if (!ok)
+ return JS_FALSE;
+ } else {
+ ok = JS_TRUE;
+ }
+ length = JSSTRING_LENGTH(str);
+ for (count = 0; index <= length; count++) {
+ ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
+ if (!ok || *rval != JSVAL_TRUE)
+ break;
+ ok = glob(cx, count, data);
+ if (!ok)
+ break;
+ if (cx->regExpStatics.lastMatch.length == 0) {
+ if (index == length)
+ break;
+ index++;
+ }
+ }
+ } else {
+ if (GET_MODE(data->flags) == MODE_REPLACE) {
+ test = JS_TRUE;
+ } else {
+ /*
+ * MODE_MATCH implies str_match is being called from a script or a
+ * scripted function. If the caller cares only about testing null
+ * vs. non-null return value, optimize away the array object that
+ * would normally be returned in *rval.
+ */
+ JS_ASSERT(*cx->fp->down->pc == JSOP_CALL ||
+ *cx->fp->down->pc == JSOP_NEW);
+ JS_ASSERT(js_CodeSpec[*cx->fp->down->pc].length == 3);
+ switch (cx->fp->down->pc[3]) {
+ case JSOP_POP:
+ case JSOP_IFEQ:
+ case JSOP_IFNE:
+ case JSOP_IFEQX:
+ case JSOP_IFNEX:
+ test = JS_TRUE;
+ break;
+ default:
+ test = JS_FALSE;
+ break;
+ }
+ }
+ ok = js_ExecuteRegExp(cx, re, str, &index, test, rval);
+ }
+
+ if (reobj) {
+ /* Tell our caller that it doesn't need to destroy data->regexp. */
+ data->flags &= ~KEEP_REGEXP;
+ } else if (!(data->flags & KEEP_REGEXP)) {
+ /* Caller didn't want to keep data->regexp, so null and destroy it. */
+ data->regexp = NULL;
+ js_DestroyRegExp(cx, re);
+ }
+ return ok;
+}
+
+typedef struct MatchData {
+ GlobData base;
+ jsval *arrayval; /* NB: local root pointer */
+} MatchData;
+
+static JSBool
+match_glob(JSContext *cx, jsint count, GlobData *data)
+{
+ MatchData *mdata;
+ JSObject *arrayobj;
+ JSSubString *matchsub;
+ JSString *matchstr;
+ jsval v;
+
+ mdata = (MatchData *)data;
+ arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval);
+ if (!arrayobj) {
+ arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
+ if (!arrayobj)
+ return JS_FALSE;
+ *mdata->arrayval = OBJECT_TO_JSVAL(arrayobj);
+ }
+ matchsub = &cx->regExpStatics.lastMatch;
+ matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length, 0);
+ if (!matchstr)
+ return JS_FALSE;
+ v = STRING_TO_JSVAL(matchstr);
+ return js_SetProperty(cx, arrayobj, INT_TO_JSVAL(count), &v);
+}
+
+static JSBool
+str_match(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ MatchData mdata;
+ JSBool ok;
+
+ mdata.base.flags = MODE_MATCH;
+ mdata.base.optarg = 1;
+ mdata.arrayval = &argv[2];
+ *mdata.arrayval = JSVAL_NULL;
+ ok = match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval);
+ if (ok && !JSVAL_IS_NULL(*mdata.arrayval))
+ *rval = *mdata.arrayval;
+ return ok;
+}
+
+static JSBool
+str_search(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ GlobData data;
+
+ data.flags = MODE_SEARCH;
+ data.optarg = 1;
+ return match_or_replace(cx, obj, argc, argv, NULL, &data, rval);
+}
+
+typedef struct ReplaceData {
+ GlobData base; /* base struct state */
+ JSObject *lambda; /* replacement function object or null */
+ JSString *repstr; /* replacement string */
+ jschar *dollar; /* null or pointer to first $ in repstr */
+ jschar *dollarEnd; /* limit pointer for js_strchr_limit */
+ jschar *chars; /* result chars, null initially */
+ size_t length; /* result length, 0 initially */
+ jsint index; /* index in result of next replacement */
+ jsint leftIndex; /* left context index in base.str->chars */
+ JSSubString dollarStr; /* for "$$" interpret_dollar result */
+} ReplaceData;
+
+static JSSubString *
+interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
+{
+ JSRegExpStatics *res;
+ jschar dc, *cp;
+ uintN num, tmp;
+ JSString *str;
+
+ JS_ASSERT(*dp == '$');
+
+ /*
+ * Allow a real backslash (literal "\\" before "$1") to escape "$1", e.g.
+ * Do this only for versions strictly less than ECMAv3.
+ */
+ if (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
+ if (dp > JSSTRING_CHARS(rdata->repstr) && dp[-1] == '\\')
+ return NULL;
+ }
+
+ /* Interpret all Perl match-induced dollar variables. */
+ res = &cx->regExpStatics;
+ dc = dp[1];
+ if (JS7_ISDEC(dc)) {
+ if (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
+ if (dc == '0')
+ return NULL;
+
+ /* Check for overflow to avoid gobbling arbitrary decimal digits. */
+ num = 0;
+ cp = dp;
+ while ((dc = *++cp) != 0 && JS7_ISDEC(dc)) {
+ tmp = 10 * num + JS7_UNDEC(dc);
+ if (tmp < num)
+ break;
+ num = tmp;
+ }
+ } else { /* ECMA 3, 1-9 or 01-99 */
+ num = JS7_UNDEC(dc);
+ if (num > res->parenCount)
+ return NULL;
+ cp = dp + 2;
+ dc = *cp;
+ if ((dc != 0) && JS7_ISDEC(dc)) {
+ tmp = 10 * num + JS7_UNDEC(dc);
+ if (tmp <= res->parenCount) {
+ cp++;
+ num = tmp;
+ }
+ }
+ if (num == 0)
+ return NULL;
+ }
+ /* Adjust num from 1 $n-origin to 0 array-index-origin. */
+ num--;
+ *skip = cp - dp;
+ return REGEXP_PAREN_SUBSTRING(res, num);
+ }
+
+ *skip = 2;
+ switch (dc) {
+ case '$':
+ rdata->dollarStr.chars = dp;
+ rdata->dollarStr.length = 1;
+ return &rdata->dollarStr;
+ case '&':
+ return &res->lastMatch;
+ case '+':
+ return &res->lastParen;
+ case '`':
+ if (cx->version == JSVERSION_1_2) {
+ /*
+ * JS1.2 imitated the Perl4 bug where left context at each step
+ * in an iterative use of a global regexp started from last match,
+ * not from the start of the target string. But Perl4 does start
+ * $` at the beginning of the target string when it is used in a
+ * substitution, so we emulate that special case here.
+ */
+ str = rdata->base.str;
+ res->leftContext.chars = JSSTRING_CHARS(str);
+ res->leftContext.length = res->lastMatch.chars
+ - JSSTRING_CHARS(str);
+ }
+ return &res->leftContext;
+ case '\'':
+ return &res->rightContext;
+ }
+ return NULL;
+}
+
+static JSBool
+find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
+{
+ JSString *repstr;
+ size_t replen, skip;
+ jschar *dp, *ep;
+ JSSubString *sub;
+#if JS_HAS_REPLACE_LAMBDA
+ JSObject *lambda;
+
+ lambda = rdata->lambda;
+ if (lambda) {
+ uintN argc, i, j, m, n, p;
+ jsval *sp, *oldsp, rval;
+ void *mark;
+ JSStackFrame *fp;
+ JSBool ok;
+
+ /*
+ * Save the rightContext from the current regexp, since it
+ * gets stuck at the end of the replacement string and may
+ * be clobbered by a RegExp usage in the lambda function.
+ */
+ JSSubString saveRightContext = cx->regExpStatics.rightContext;
+
+ /*
+ * In the lambda case, not only do we find the replacement string's
+ * length, we compute repstr and return it via rdata for use within
+ * do_replace. The lambda is called with arguments ($&, $1, $2, ...,
+ * index, input), i.e., all the properties of a regexp match array.
+ * For $&, etc., we must create string jsvals from cx->regExpStatics.
+ * We grab up stack space to keep the newborn strings GC-rooted.
+ */
+ p = rdata->base.regexp->parenCount;
+ argc = 1 + p + 2;
+ sp = js_AllocStack(cx, 2 + argc, &mark);
+ if (!sp)
+ return JS_FALSE;
+
+ /* Push lambda and its 'this' parameter. */
+ *sp++ = OBJECT_TO_JSVAL(lambda);
+ *sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda));
+
+#define PUSH_REGEXP_STATIC(sub) \
+ JS_BEGIN_MACRO \
+ JSString *str = js_NewStringCopyN(cx, \
+ cx->regExpStatics.sub.chars, \
+ cx->regExpStatics.sub.length, \
+ 0); \
+ if (!str) { \
+ ok = JS_FALSE; \
+ goto lambda_out; \
+ } \
+ *sp++ = STRING_TO_JSVAL(str); \
+ JS_END_MACRO
+
+ /* Push $&, $1, $2, ... */
+ PUSH_REGEXP_STATIC(lastMatch);
+ i = 0;
+ m = cx->regExpStatics.parenCount;
+ n = JS_MIN(m, 9);
+ for (j = 0; i < n; i++, j++)
+ PUSH_REGEXP_STATIC(parens[j]);
+ for (j = 0; i < m; i++, j++)
+ PUSH_REGEXP_STATIC(moreParens[j]);
+
+#undef PUSH_REGEXP_STATIC
+
+ /* Make sure to push undefined for any unmatched parens. */
+ for (; i < p; i++)
+ *sp++ = JSVAL_VOID;
+
+ /* Push match index and input string. */
+ *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
+ *sp++ = STRING_TO_JSVAL(rdata->base.str);
+
+ /* Lift current frame to include the args and do the call. */
+ fp = cx->fp;
+ oldsp = fp->sp;
+ fp->sp = sp;
+ ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
+ rval = fp->sp[-1];
+ fp->sp = oldsp;
+
+ if (ok) {
+ /*
+ * NB: we count on the newborn string root to hold any string
+ * created by this js_ValueToString that would otherwise be GC-
+ * able, until we use rdata->repstr in do_replace.
+ */
+ repstr = js_ValueToString(cx, rval);
+ if (!repstr) {
+ ok = JS_FALSE;
+ } else {
+ rdata->repstr = repstr;
+ *sizep = JSSTRING_LENGTH(repstr);
+ }
+ }
+
+ lambda_out:
+ js_FreeStack(cx, mark);
+ cx->regExpStatics.rightContext = saveRightContext;
+ return ok;
+ }
+#endif /* JS_HAS_REPLACE_LAMBDA */
+
+ repstr = rdata->repstr;
+ replen = JSSTRING_LENGTH(repstr);
+ for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
+ dp = js_strchr_limit(dp, '$', ep)) {
+ sub = interpret_dollar(cx, dp, rdata, &skip);
+ if (sub) {
+ replen += sub->length - skip;
+ dp += skip;
+ }
+ else
+ dp++;
+ }
+ *sizep = replen;
+ return JS_TRUE;
+}
+
+static void
+do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
+{
+ JSString *repstr;
+ jschar *bp, *cp, *dp, *ep;
+ size_t len, skip;
+ JSSubString *sub;
+
+ repstr = rdata->repstr;
+ bp = cp = JSSTRING_CHARS(repstr);
+ for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
+ dp = js_strchr_limit(dp, '$', ep)) {
+ len = dp - cp;
+ js_strncpy(chars, cp, len);
+ chars += len;
+ cp = dp;
+ sub = interpret_dollar(cx, dp, rdata, &skip);
+ if (sub) {
+ len = sub->length;
+ js_strncpy(chars, sub->chars, len);
+ chars += len;
+ cp += skip;
+ dp += skip;
+ } else {
+ dp++;
+ }
+ }
+ js_strncpy(chars, cp, JSSTRING_LENGTH(repstr) - (cp - bp));
+}
+
+static JSBool
+replace_glob(JSContext *cx, jsint count, GlobData *data)
+{
+ ReplaceData *rdata;
+ JSString *str;
+ size_t leftoff, leftlen, replen, growth;
+ const jschar *left;
+ jschar *chars;
+
+ rdata = (ReplaceData *)data;
+ str = data->str;
+ leftoff = rdata->leftIndex;
+ left = JSSTRING_CHARS(str) + leftoff;
+ leftlen = cx->regExpStatics.lastMatch.chars - left;
+ rdata->leftIndex = cx->regExpStatics.lastMatch.chars - JSSTRING_CHARS(str);
+ rdata->leftIndex += cx->regExpStatics.lastMatch.length;
+ if (!find_replen(cx, rdata, &replen))
+ return JS_FALSE;
+ growth = leftlen + replen;
+ chars = (jschar *)
+ (rdata->chars
+ ? JS_realloc(cx, rdata->chars, (rdata->length + growth + 1)
+ * sizeof(jschar))
+ : JS_malloc(cx, (growth + 1) * sizeof(jschar)));
+ if (!chars) {
+ JS_free(cx, rdata->chars);
+ rdata->chars = NULL;
+ return JS_FALSE;
+ }
+ rdata->chars = chars;
+ rdata->length += growth;
+ chars += rdata->index;
+ rdata->index += growth;
+ js_strncpy(chars, left, leftlen);
+ chars += leftlen;
+ do_replace(cx, rdata, chars);
+ return JS_TRUE;
+}
+
+static JSBool
+str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSObject *lambda;
+ JSString *repstr, *str;
+ ReplaceData rdata;
+ JSBool ok;
+ jschar *chars;
+ size_t leftlen, rightlen, length;
+
+#if JS_HAS_REPLACE_LAMBDA
+ if (JS_TypeOfValue(cx, argv[1]) == JSTYPE_FUNCTION) {
+ lambda = JSVAL_TO_OBJECT(argv[1]);
+ repstr = NULL;
+ } else
+#endif
+ {
+ if (!JS_ConvertValue(cx, argv[1], JSTYPE_STRING, &argv[1]))
+ return JS_FALSE;
+ repstr = JSVAL_TO_STRING(argv[1]);
+ lambda = NULL;
+ }
+
+ /*
+ * For ECMA Edition 3, the first argument is to be converted to a string
+ * to match in a "flat" sense (without regular expression metachars having
+ * special meanings) UNLESS the first arg is a RegExp object.
+ */
+ rdata.base.flags = MODE_REPLACE | KEEP_REGEXP;
+ if (cx->version == JSVERSION_DEFAULT || cx->version > JSVERSION_1_4)
+ rdata.base.flags |= FORCE_FLAT;
+ rdata.base.optarg = 2;
+
+ rdata.lambda = lambda;
+ rdata.repstr = repstr;
+ if (repstr) {
+ rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr);
+ rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$',
+ rdata.dollarEnd);
+ } else {
+ rdata.dollar = rdata.dollarEnd = NULL;
+ }
+ rdata.chars = NULL;
+ rdata.length = 0;
+ rdata.index = 0;
+ rdata.leftIndex = 0;
+
+ ok = match_or_replace(cx, obj, argc, argv, replace_glob, &rdata.base, rval);
+ if (!ok)
+ return JS_FALSE;
+
+ if (!rdata.chars) {
+ if ((rdata.base.flags & GLOBAL_REGEXP) || *rval != JSVAL_TRUE) {
+ /* Didn't match even once. */
+ *rval = STRING_TO_JSVAL(rdata.base.str);
+ goto out;
+ }
+ leftlen = cx->regExpStatics.leftContext.length;
+ ok = find_replen(cx, &rdata, &length);
+ if (!ok)
+ goto out;
+ length += leftlen;
+ chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
+ if (!chars) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen);
+ do_replace(cx, &rdata, chars + leftlen);
+ rdata.chars = chars;
+ rdata.length = length;
+ }
+
+ rightlen = cx->regExpStatics.rightContext.length;
+ length = rdata.length + rightlen;
+ chars = (jschar *)
+ JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar));
+ if (!chars) {
+ JS_free(cx, rdata.chars);
+ ok = JS_FALSE;
+ goto out;
+ }
+ js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars,
+ rightlen);
+ chars[length] = 0;
+
+ str = js_NewString(cx, chars, length, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ ok = JS_FALSE;
+ goto out;
+ }
+ *rval = STRING_TO_JSVAL(str);
+
+out:
+ /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */
+ if (rdata.base.flags & KEEP_REGEXP)
+ js_DestroyRegExp(cx, rdata.base.regexp);
+ return ok;
+}
+#endif /* JS_HAS_REGEXPS */
+
+/*
+ * Subroutine used by str_split to find the next split point in str, starting
+ * at offset *ip and looking either for the separator substring given by sep,
+ * or for the next re match. In the re case, return the matched separator in
+ * *sep, and the possibly updated offset in *ip.
+ *
+ * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
+ * separator occurrence if found, or str->length if no separator is found.
+ */
+static jsint
+find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
+ JSSubString *sep)
+{
+ jsint i, j, k;
+ jschar *chars;
+ size_t length;
+
+ /*
+ * Stop if past end of string. If at end of string, we will compare the
+ * null char stored there (by js_NewString*) to sep->chars[j] in the while
+ * loop at the end of this function, so that
+ *
+ * "ab,".split(',') => ["ab", ""]
+ *
+ * and the resulting array converts back to the string "ab," for symmetry.
+ * However, we ape Perl and do this only if there is a sufficiently large
+ * limit argument (see str_split).
+ */
+ i = *ip;
+ if ((size_t)i > JSSTRING_LENGTH(str))
+ return -1;
+
+ /*
+ * Perl4 special case for str.split(' '), only if the user has selected
+ * JavaScript1.2 explicitly. Split on whitespace, and skip leading w/s.
+ * Strange but true, apparently modeled after awk.
+ *
+ * NB: we set sep->length to the length of the w/s run, so we must test
+ * sep->chars[1] == 0 to make sure sep is just one space.
+ */
+ chars = JSSTRING_CHARS(str);
+ length = JSSTRING_LENGTH(str);
+ if (cx->version == JSVERSION_1_2 &&
+ !re && *sep->chars == ' ' && sep->chars[1] == 0) {
+
+ /* Skip leading whitespace if at front of str. */
+ if (i == 0) {
+ while (JS_ISSPACE(chars[i]))
+ i++;
+ *ip = i;
+ }
+
+ /* Don't delimit whitespace at end of string. */
+ if ((size_t)i == length)
+ return -1;
+
+ /* Skip over the non-whitespace chars. */
+ while ((size_t)i < length && !JS_ISSPACE(chars[i]))
+ i++;
+
+ /* Now skip the next run of whitespace. */
+ j = i;
+ while ((size_t)j < length && JS_ISSPACE(chars[j]))
+ j++;
+
+ /* Update sep->length to count delimiter chars. */
+ sep->length = (size_t)(j - i);
+ return i;
+ }
+
+#if JS_HAS_REGEXPS
+ /*
+ * Match a regular expression against the separator at or above index i.
+ * Call js_ExecuteRegExp with true for the test argument. On successful
+ * match, get the separator from cx->regExpStatics.lastMatch.
+ */
+ if (re) {
+ size_t index;
+ jsval rval;
+
+ again:
+ /* JS1.2 deviated from Perl by never matching at end of string. */
+ index = (size_t)i;
+ if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval))
+ return -2;
+ if (rval != JSVAL_TRUE) {
+ /* Mismatch: ensure our caller advances i past end of string. */
+ sep->length = 1;
+ return length;
+ }
+ i = (jsint)index;
+ *sep = cx->regExpStatics.lastMatch;
+ if (sep->length == 0) {
+ /*
+ * Empty string match: never split on an empty match at the start
+ * of a find_split cycle. Same rule as for an empty global match
+ * in match_or_replace.
+ */
+ if (i == *ip) {
+ /*
+ * "Bump-along" to avoid sticking at an empty match, but don't
+ * bump past end of string -- our caller must do that by adding
+ * sep->length to our return value.
+ */
+ if ((size_t)i == length) {
+ if (cx->version == JSVERSION_1_2) {
+ sep->length = 1;
+ return i;
+ }
+ return -1;
+ }
+ i++;
+ goto again;
+ }
+ }
+ JS_ASSERT((size_t)i >= sep->length);
+ return i - sep->length;
+ }
+#endif /* JS_HAS_REGEXPS */
+
+ /*
+ * Deviate from ECMA by never splitting an empty string by any separator
+ * string into a non-empty array (an array of length 1 that contains the
+ * empty string).
+ */
+ if (!JSVERSION_IS_ECMA(cx->version) && length == 0)
+ return -1;
+
+ /*
+ * Special case: if sep is the empty string, split str into one character
+ * substrings. Let our caller worry about whether to split once at end of
+ * string into an empty substring.
+ *
+ * For 1.2 compatibility, at the end of the string, we return the length as
+ * the result, and set the separator length to 1 -- this allows the caller
+ * to include an additional null string at the end of the substring list.
+ */
+ if (sep->length == 0) {
+ if (cx->version == JSVERSION_1_2) {
+ if ((size_t)i == length) {
+ sep->length = 1;
+ return i;
+ }
+ return i + 1;
+ }
+ return ((size_t)i == length) ? -1 : i + 1;
+ }
+
+ /*
+ * Now that we know sep is non-empty, search starting at i in str for an
+ * occurrence of all of sep's chars. If we find them, return the index of
+ * the first separator char. Otherwise, return length.
+ */
+ j = 0;
+ while ((size_t)(k = i + j) < length) {
+ if (chars[k] == sep->chars[j]) {
+ if ((size_t)++j == sep->length)
+ return i;
+ } else {
+ i++;
+ j = 0;
+ }
+ }
+ return k;
+}
+
+static JSBool
+str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str, *sub;
+ JSObject *arrayobj;
+ jsval v;
+ JSBool ok, limited;
+ JSRegExp *re;
+ JSSubString *sep, tmp;
+ jsdouble d;
+ jsint i, j;
+ uint32 len, limit;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
+ if (!arrayobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(arrayobj);
+
+ if (argc == 0) {
+ v = STRING_TO_JSVAL(str);
+ ok = JS_SetElement(cx, arrayobj, 0, &v);
+ } else {
+#if JS_HAS_REGEXPS
+ if (JSVAL_IS_REGEXP(cx, argv[0])) {
+ re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
+ sep = &tmp;
+
+ /* Set a magic value so we can detect a successful re match. */
+ sep->chars = NULL;
+ } else
+#endif
+ {
+ JSString *str2 = js_ValueToString(cx, argv[0]);
+ if (!str2)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str2);
+
+ /*
+ * Point sep at a local copy of str2's header because find_split
+ * will modify sep->length.
+ */
+ tmp.length = JSSTRING_LENGTH(str2);
+ tmp.chars = JSSTRING_CHARS(str2);
+ sep = &tmp;
+ re = NULL;
+ }
+
+ /* Use the second argument as the split limit, if given. */
+ limited = (argc > 1) && !JSVAL_IS_VOID(argv[1]);
+ limit = 0; /* Avoid warning. */
+ if (limited) {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+
+ /* Clamp limit between 0 and 1 + string length. */
+ if (!js_DoubleToECMAUint32(cx, d, &limit))
+ return JS_FALSE;
+ if (limit > JSSTRING_LENGTH(str))
+ limit = 1 + JSSTRING_LENGTH(str);
+ }
+
+ len = i = 0;
+ while ((j = find_split(cx, str, re, &i, sep)) >= 0) {
+ if (limited && len >= limit)
+ break;
+ sub = js_NewDependentString(cx, str, i, (size_t)(j - i), 0);
+ if (!sub)
+ return JS_FALSE;
+ v = STRING_TO_JSVAL(sub);
+ if (!JS_SetElement(cx, arrayobj, len, &v))
+ return JS_FALSE;
+ len++;
+#if JS_HAS_REGEXPS
+ /*
+ * Imitate perl's feature of including parenthesized substrings
+ * that matched part of the delimiter in the new array, after the
+ * split substring that was delimited.
+ */
+ if (re && sep->chars) {
+ uintN num;
+ JSSubString *parsub;
+
+ for (num = 0; num < cx->regExpStatics.parenCount; num++) {
+ if (limited && len >= limit)
+ break;
+ parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num);
+ sub = js_NewStringCopyN(cx, parsub->chars, parsub->length,
+ 0);
+ if (!sub)
+ return JS_FALSE;
+ v = STRING_TO_JSVAL(sub);
+ if (!JS_SetElement(cx, arrayobj, len, &v))
+ return JS_FALSE;
+ len++;
+ }
+ sep->chars = NULL;
+ }
+#endif
+ i = j + sep->length;
+ if (!JSVERSION_IS_ECMA(cx->version)) {
+ /*
+ * Deviate from ECMA to imitate Perl, which omits a final
+ * split unless a limit argument is given and big enough.
+ */
+ if (!limited && (size_t)i == JSSTRING_LENGTH(str))
+ break;
+ }
+ }
+ ok = (j != -2);
+ }
+ return ok;
+}
+
+#if JS_HAS_PERL_SUBSTR
+static JSBool
+str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ jsdouble d;
+ jsdouble length, begin, end;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+
+ if (argc != 0) {
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ length = JSSTRING_LENGTH(str);
+ begin = js_DoubleToInteger(d);
+ if (begin < 0) {
+ begin += length;
+ if (begin < 0)
+ begin = 0;
+ } else if (begin > length) {
+ begin = length;
+ }
+
+ if (argc == 1) {
+ end = length;
+ } else {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+ end = js_DoubleToInteger(d);
+ if (end < 0)
+ end = 0;
+ end += begin;
+ if (end > length)
+ end = length;
+ }
+
+ str = js_NewDependentString(cx, str, (size_t)begin,
+ (size_t)(end - begin), 0);
+ if (!str)
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif /* JS_HAS_PERL_SUBSTR */
+
+#if JS_HAS_SEQUENCE_OPS
+/*
+ * Python-esque sequence operations.
+ */
+static JSBool
+str_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str, *str2;
+ uintN i;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ for (i = 0; i < argc; i++) {
+ str2 = js_ValueToString(cx, argv[i]);
+ if (!str2)
+ return JS_FALSE;
+ argv[i] = STRING_TO_JSVAL(str2);
+
+ str = js_ConcatStrings(cx, str, str2);
+ if (!str)
+ return JS_FALSE;
+ }
+
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ jsdouble d;
+ jsdouble length, begin, end;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ if (argc != 0) {
+ if (!js_ValueToNumber(cx, argv[0], &d))
+ return JS_FALSE;
+ length = JSSTRING_LENGTH(str);
+ begin = js_DoubleToInteger(d);
+ if (begin < 0) {
+ begin += length;
+ if (begin < 0)
+ begin = 0;
+ } else if (begin > length) {
+ begin = length;
+ }
+
+ if (argc == 1) {
+ end = length;
+ } else {
+ if (!js_ValueToNumber(cx, argv[1], &d))
+ return JS_FALSE;
+ end = js_DoubleToInteger(d);
+ if (end < 0) {
+ end += length;
+ if (end < 0)
+ end = 0;
+ } else if (end > length) {
+ end = length;
+ }
+ if (end < begin)
+ end = begin;
+ }
+
+ str = js_NewDependentString(cx, str, (size_t)begin,
+ (size_t)(end - begin), 0);
+ if (!str)
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+#endif /* JS_HAS_SEQUENCE_OPS */
+
+#if JS_HAS_STR_HTML_HELPERS
+/*
+ * HTML composition aids.
+ */
+static JSBool
+tagify(JSContext *cx, JSObject *obj, jsval *argv,
+ const char *begin, const jschar *param, const char *end,
+ jsval *rval)
+{
+ JSString *str;
+ jschar *tagbuf;
+ size_t beglen, endlen, parlen, taglen;
+ size_t i, j;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ argv[-1] = STRING_TO_JSVAL(str);
+
+ if (!end)
+ end = begin;
+
+ beglen = strlen(begin);
+ taglen = 1 + beglen + 1; /* '<begin' + '>' */
+ parlen = 0; /* Avoid warning. */
+ if (param) {
+ parlen = js_strlen(param);
+ taglen += 2 + parlen + 1; /* '="param"' */
+ }
+ endlen = strlen(end);
+ taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1; /* 'str</end>' */
+
+ tagbuf = (jschar *) JS_malloc(cx, (taglen + 1) * sizeof(jschar));
+ if (!tagbuf)
+ return JS_FALSE;
+
+ j = 0;
+ tagbuf[j++] = '<';
+ for (i = 0; i < beglen; i++)
+ tagbuf[j++] = (jschar)begin[i];
+ if (param) {
+ tagbuf[j++] = '=';
+ tagbuf[j++] = '"';
+ js_strncpy(&tagbuf[j], param, parlen);
+ j += parlen;
+ tagbuf[j++] = '"';
+ }
+ tagbuf[j++] = '>';
+ js_strncpy(&tagbuf[j], JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
+ j += JSSTRING_LENGTH(str);
+ tagbuf[j++] = '<';
+ tagbuf[j++] = '/';
+ for (i = 0; i < endlen; i++)
+ tagbuf[j++] = (jschar)end[i];
+ tagbuf[j++] = '>';
+ JS_ASSERT(j == taglen);
+ tagbuf[j] = 0;
+
+ str = js_NewString(cx, tagbuf, taglen, 0);
+ if (!str) {
+ free((char *)tagbuf);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+tagify_value(JSContext *cx, JSObject *obj, jsval *argv,
+ const char *begin, const char *end,
+ jsval *rval)
+{
+ JSString *param;
+
+ param = js_ValueToString(cx, argv[0]);
+ if (!param)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(param);
+ return tagify(cx, obj, argv, begin, JSSTRING_CHARS(param), end, rval);
+}
+
+static JSBool
+str_bold(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "b", NULL, NULL, rval);
+}
+
+static JSBool
+str_italics(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "i", NULL, NULL, rval);
+}
+
+static JSBool
+str_fixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "tt", NULL, NULL, rval);
+}
+
+static JSBool
+str_fontsize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify_value(cx, obj, argv, "font size", "font", rval);
+}
+
+static JSBool
+str_fontcolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ return tagify_value(cx, obj, argv, "font color", "font", rval);
+}
+
+static JSBool
+str_link(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify_value(cx, obj, argv, "a href", "a", rval);
+}
+
+static JSBool
+str_anchor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify_value(cx, obj, argv, "a name", "a", rval);
+}
+
+static JSBool
+str_strike(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "strike", NULL, NULL, rval);
+}
+
+static JSBool
+str_small(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "small", NULL, NULL, rval);
+}
+
+static JSBool
+str_big(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "big", NULL, NULL, rval);
+}
+
+static JSBool
+str_blink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "blink", NULL, NULL, rval);
+}
+
+static JSBool
+str_sup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "sup", NULL, NULL, rval);
+}
+
+static JSBool
+str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ return tagify(cx, obj, argv, "sub", NULL, NULL, rval);
+}
+#endif /* JS_HAS_STR_HTML_HELPERS */
+
+static JSFunctionSpec string_methods[] = {
+#if JS_HAS_TOSOURCE
+ {"quote", str_quote, 0,0,0},
+ {js_toSource_str, str_toSource, 0,0,0},
+#endif
+
+ /* Java-like methods. */
+ {js_toString_str, str_toString, 0,0,0},
+ {js_valueOf_str, str_valueOf, 0,0,0},
+ {"substring", str_substring, 2,0,0},
+ {"toLowerCase", str_toLowerCase, 0,0,0},
+ {"toUpperCase", str_toUpperCase, 0,0,0},
+ {"charAt", str_charAt, 1,0,0},
+ {"charCodeAt", str_charCodeAt, 1,0,0},
+ {"indexOf", str_indexOf, 1,0,0},
+ {"lastIndexOf", str_lastIndexOf, 1,0,0},
+ {"toLocaleLowerCase", str_toLocaleLowerCase, 0,0,0},
+ {"toLocaleUpperCase", str_toLocaleUpperCase, 0,0,0},
+ {"localeCompare", str_localeCompare, 1,0,0},
+
+ /* Perl-ish methods (search is actually Python-esque). */
+#if JS_HAS_REGEXPS
+ {"match", str_match, 1,0,2},
+ {"search", str_search, 1,0,0},
+ {"replace", str_replace, 2,0,0},
+ {"split", str_split, 2,0,0},
+#endif
+#if JS_HAS_PERL_SUBSTR
+ {"substr", str_substr, 2,0,0},
+#endif
+
+ /* Python-esque sequence methods. */
+#if JS_HAS_SEQUENCE_OPS
+ {"concat", str_concat, 0,0,0},
+ {"slice", str_slice, 0,0,0},
+#endif
+
+ /* HTML string methods. */
+#if JS_HAS_STR_HTML_HELPERS
+ {"bold", str_bold, 0,0,0},
+ {"italics", str_italics, 0,0,0},
+ {"fixed", str_fixed, 0,0,0},
+ {"fontsize", str_fontsize, 1,0,0},
+ {"fontcolor", str_fontcolor, 1,0,0},
+ {"link", str_link, 1,0,0},
+ {"anchor", str_anchor, 1,0,0},
+ {"strike", str_strike, 0,0,0},
+ {"small", str_small, 0,0,0},
+ {"big", str_big, 0,0,0},
+ {"blink", str_blink, 0,0,0},
+ {"sup", str_sup, 0,0,0},
+ {"sub", str_sub, 0,0,0},
+#endif
+
+ {0,0,0,0,0}
+};
+
+static JSBool
+String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+
+ if (argc > 0) {
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ } else {
+ str = cx->runtime->emptyString;
+ }
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+ }
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
+ return JS_TRUE;
+}
+
+static JSBool
+str_fromCharCode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jschar *chars;
+ uintN i;
+ uint16 code;
+ JSString *str;
+
+ chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar));
+ if (!chars)
+ return JS_FALSE;
+ for (i = 0; i < argc; i++) {
+ if (!js_ValueToUint16(cx, argv[i], &code)) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+ chars[i] = (jschar)code;
+ }
+ chars[i] = 0;
+ str = js_NewString(cx, chars, argc, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSFunctionSpec string_static_methods[] = {
+ {"fromCharCode", str_fromCharCode, 1,0,0},
+ {0,0,0,0,0}
+};
+
+static JSHashTable *deflated_string_cache;
+#ifdef DEBUG
+static uint32 deflated_string_cache_bytes;
+#endif
+#ifdef JS_THREADSAFE
+static JSLock *deflated_string_cache_lock;
+#endif
+
+JSBool
+js_InitStringGlobals(void)
+{
+#ifdef JS_THREADSAFE
+ /* Must come through here once in primordial thread to init safely! */
+ if (!deflated_string_cache_lock) {
+ deflated_string_cache_lock = JS_NEW_LOCK();
+ if (!deflated_string_cache_lock)
+ return JS_FALSE;
+ }
+#endif
+ return JS_TRUE;
+}
+
+void
+js_FreeStringGlobals()
+{
+ if (deflated_string_cache) {
+ JS_HashTableDestroy(deflated_string_cache);
+ deflated_string_cache = NULL;
+ }
+#ifdef JS_THREADSAFE
+ if (deflated_string_cache_lock) {
+ JS_DESTROY_LOCK(deflated_string_cache_lock);
+ deflated_string_cache_lock = NULL;
+ }
+#endif
+}
+
+JSBool
+js_InitRuntimeStringState(JSContext *cx)
+{
+ JSRuntime *rt;
+ JSString *empty;
+
+ rt = cx->runtime;
+ JS_ASSERT(!rt->emptyString);
+
+ /* Make a permanently locked empty string. */
+ empty = js_NewStringCopyN(cx, js_empty_ucstr, 0, GCF_LOCK);
+ if (!empty)
+ return JS_FALSE;
+
+ /* Atomize it for scripts that use '' + x to convert x to string. */
+ if (!js_AtomizeString(cx, empty, ATOM_PINNED))
+ return JS_FALSE;
+
+ rt->emptyString = empty;
+ return JS_TRUE;
+}
+
+void
+js_FinishRuntimeStringState(JSContext *cx)
+{
+ JSRuntime *rt = cx->runtime;
+
+ js_UnlockGCThingRT(rt, rt->emptyString);
+ rt->emptyString = NULL;
+}
+
+JSObject *
+js_InitStringClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+
+ /* Define the escape, unescape functions in the global object. */
+ if (!JS_DefineFunctions(cx, obj, string_functions))
+ return NULL;
+
+ proto = JS_InitClass(cx, obj, NULL, &string_class, String, 1,
+ string_props, string_methods,
+ NULL, string_static_methods);
+ if (!proto)
+ return NULL;
+ OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE,
+ STRING_TO_JSVAL(cx->runtime->emptyString));
+ return proto;
+}
+
+JSString *
+js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
+{
+ JSString *str;
+
+ if (length > JSSTRING_LENGTH_MASK) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+
+ str = (JSString *) js_AllocGCThing(cx, gcflag | GCX_STRING);
+ if (!str)
+ return NULL;
+ str->length = length;
+ str->chars = chars;
+#ifdef DEBUG
+ {
+ JSRuntime *rt = cx->runtime;
+ JS_RUNTIME_METER(rt, liveStrings);
+ JS_RUNTIME_METER(rt, totalStrings);
+ JS_LOCK_RUNTIME_VOID(rt,
+ (rt->lengthSum += (double)length,
+ rt->lengthSquaredSum += (double)length * (double)length));
+ }
+#endif
+ return str;
+}
+
+JSString *
+js_NewDependentString(JSContext *cx, JSString *base, size_t start,
+ size_t length, uintN gcflag)
+{
+ JSDependentString *ds;
+
+ if (length == 0)
+ return cx->runtime->emptyString;
+
+ if (start > JSSTRDEP_START_MASK ||
+ (start != 0 && length > JSSTRDEP_LENGTH_MASK)) {
+ return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length,
+ gcflag);
+ }
+
+ ds = (JSDependentString *) js_AllocGCThing(cx, gcflag | GCX_MUTABLE_STRING);
+ if (!ds)
+ return NULL;
+ if (start == 0) {
+ JSPREFIX_SET_LENGTH(ds, length);
+ JSPREFIX_SET_BASE(ds, base);
+ } else {
+ JSSTRDEP_SET_START_AND_LENGTH(ds, start, length);
+ JSSTRDEP_SET_BASE(ds, base);
+ }
+#ifdef DEBUG
+ {
+ JSRuntime *rt = cx->runtime;
+ JS_RUNTIME_METER(rt, liveDependentStrings);
+ JS_RUNTIME_METER(rt, totalDependentStrings);
+ JS_RUNTIME_METER(rt, liveStrings);
+ JS_RUNTIME_METER(rt, totalStrings);
+ JS_LOCK_RUNTIME_VOID(rt,
+ (rt->strdepLengthSum += (double)length,
+ rt->strdepLengthSquaredSum += (double)length * (double)length));
+ JS_LOCK_RUNTIME_VOID(rt,
+ (rt->lengthSum += (double)length,
+ rt->lengthSquaredSum += (double)length * (double)length));
+ }
+#endif
+ return (JSString *)ds;
+}
+
+#ifdef DEBUG
+#include <math.h>
+
+void printJSStringStats(JSRuntime *rt) {
+ double mean = 0., var = 0., sigma = 0.;
+ jsrefcount count = rt->totalStrings;
+ if (count > 0 && rt->lengthSum >= 0) {
+ mean = rt->lengthSum / count;
+ var = count * rt->lengthSquaredSum - rt->lengthSum * rt->lengthSum;
+ if (var < 0.0 || count <= 1)
+ var = 0.0;
+ else
+ var /= count * (count - 1);
+
+ /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
+ sigma = (var != 0.) ? sqrt(var) : 0.;
+ }
+ fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
+ (unsigned long)count, mean, sigma);
+
+ mean = var = sigma = 0.;
+ count = rt->totalDependentStrings;
+ if (count > 0 && rt->strdepLengthSum >= 0) {
+ mean = rt->strdepLengthSum / count;
+ var = count * rt->strdepLengthSquaredSum
+ - rt->strdepLengthSum * rt->strdepLengthSum;
+ if (var < 0.0 || count <= 1)
+ var = 0.0;
+ else
+ var /= count * (count - 1);
+
+ /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
+ sigma = (var != 0.) ? sqrt(var) : 0.;
+ }
+ fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
+ (unsigned long)count, mean, sigma);
+}
+#endif
+
+JSString *
+js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n, uintN gcflag)
+{
+ jschar *news;
+ JSString *str;
+
+ news = (jschar *)JS_malloc(cx, (n + 1) * sizeof(jschar));
+ if (!news)
+ return NULL;
+ js_strncpy(news, s, n);
+ news[n] = 0;
+ str = js_NewString(cx, news, n, gcflag);
+ if (!str)
+ JS_free(cx, news);
+ return str;
+}
+
+JSString *
+js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag)
+{
+ size_t n, m;
+ jschar *news;
+ JSString *str;
+
+ n = js_strlen(s);
+ m = (n + 1) * sizeof(jschar);
+ news = (jschar *) JS_malloc(cx, m);
+ if (!news)
+ return NULL;
+ memcpy(news, s, m);
+ str = js_NewString(cx, news, n, gcflag);
+ if (!str)
+ JS_free(cx, news);
+ return str;
+}
+
+JS_STATIC_DLL_CALLBACK(JSHashNumber)
+js_hash_string_pointer(const void *key)
+{
+ return (JSHashNumber)key >> JSVAL_TAGBITS;
+}
+
+void
+js_PurgeDeflatedStringCache(JSString *str)
+{
+ JSHashNumber hash;
+ JSHashEntry *he, **hep;
+
+ if (!deflated_string_cache)
+ return;
+
+ hash = js_hash_string_pointer(str);
+ JS_ACQUIRE_LOCK(deflated_string_cache_lock);
+ hep = JS_HashTableRawLookup(deflated_string_cache, hash, str);
+ he = *hep;
+ if (he) {
+#ifdef DEBUG
+ deflated_string_cache_bytes -= JSSTRING_LENGTH(str);
+#endif
+ free(he->value);
+ JS_HashTableRawRemove(deflated_string_cache, hep, he);
+ }
+ JS_RELEASE_LOCK(deflated_string_cache_lock);
+}
+
+void
+js_FinalizeString(JSContext *cx, JSString *str)
+{
+ js_FinalizeStringRT(cx->runtime, str);
+}
+
+void
+js_FinalizeStringRT(JSRuntime *rt, JSString *str)
+{
+ JSBool valid;
+
+ JS_RUNTIME_UNMETER(rt, liveStrings);
+ if (JSSTRING_IS_DEPENDENT(str)) {
+ /* If JSSTRFLAG_DEPENDENT is set, this string must be valid. */
+ JS_ASSERT(JSSTRDEP_BASE(str));
+ JS_RUNTIME_UNMETER(rt, liveDependentStrings);
+ valid = JS_TRUE;
+ } else {
+ /* A stillborn string has null chars, so is not valid. */
+ valid = (str->chars != NULL);
+ if (valid)
+ free(str->chars);
+ }
+ if (valid) {
+ js_PurgeDeflatedStringCache(str);
+ str->chars = NULL;
+ }
+ str->length = 0;
+}
+
+JSObject *
+js_StringToObject(JSContext *cx, JSString *str)
+{
+ JSObject *obj;
+
+ obj = js_NewObject(cx, &string_class, NULL, NULL);
+ if (!obj)
+ return NULL;
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
+ return obj;
+}
+
+JSString *
+js_ValueToString(JSContext *cx, jsval v)
+{
+ JSObject *obj;
+ JSString *str;
+
+ if (JSVAL_IS_OBJECT(v)) {
+ obj = JSVAL_TO_OBJECT(v);
+ if (!obj)
+ return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
+ if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
+ return NULL;
+ }
+ if (JSVAL_IS_STRING(v)) {
+ str = JSVAL_TO_STRING(v);
+ } else if (JSVAL_IS_INT(v)) {
+ str = js_NumberToString(cx, JSVAL_TO_INT(v));
+ } else if (JSVAL_IS_DOUBLE(v)) {
+ str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v));
+ } else if (JSVAL_IS_BOOLEAN(v)) {
+ str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v));
+ } else {
+ str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
+ }
+ return str;
+}
+
+JSString *
+js_ValueToSource(JSContext *cx, jsval v)
+{
+ if (JSVAL_IS_STRING(v))
+ return js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
+ if (JSVAL_IS_PRIMITIVE(v)) {
+ /* Special case to preserve negative zero, _contra_ toString. */
+ if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) {
+ /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
+ static const jschar js_negzero_ucNstr[] = {'-', '0'};
+
+ return js_NewStringCopyN(cx, js_negzero_ucNstr, 2, 0);
+ }
+ } else {
+ if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v),
+ cx->runtime->atomState.toSourceAtom,
+ 0, NULL, &v)) {
+ return NULL;
+ }
+ }
+ return js_ValueToString(cx, v);
+}
+
+JSHashNumber
+js_HashString(JSString *str)
+{
+ JSHashNumber h;
+ const jschar *s;
+ size_t n;
+
+ h = 0;
+ for (s = JSSTRING_CHARS(str), n = JSSTRING_LENGTH(str); n; s++, n--)
+ h = (h >> (JS_HASH_BITS - 4)) ^ (h << 4) ^ *s;
+ return h;
+}
+
+intN
+js_CompareStrings(JSString *str1, JSString *str2)
+{
+ size_t l1, l2, n, i;
+ const jschar *s1, *s2;
+ intN cmp;
+
+ l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
+ s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2);
+ n = JS_MIN(l1, l2);
+ for (i = 0; i < n; i++) {
+ cmp = s1[i] - s2[i];
+ if (cmp != 0)
+ return cmp;
+ }
+ return (intN)(l1 - l2);
+}
+
+size_t
+js_strlen(const jschar *s)
+{
+ const jschar *t;
+
+ for (t = s; *t != 0; t++)
+ continue;
+ return (size_t)(t - s);
+}
+
+jschar *
+js_strchr(const jschar *s, jschar c)
+{
+ while (*s != 0) {
+ if (*s == c)
+ return (jschar *)s;
+ s++;
+ }
+ return NULL;
+}
+
+jschar *
+js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
+{
+ while (s < limit) {
+ if (*s == c)
+ return (jschar *)s;
+ s++;
+ }
+ return NULL;
+}
+
+const jschar *
+js_SkipWhiteSpace(const jschar *s)
+{
+ /* JS_ISSPACE is false on a null. */
+ while (JS_ISSPACE(*s))
+ s++;
+ return s;
+}
+
+#define INFLATE_STRING_BODY \
+ for (i = 0; i < length; i++) \
+ chars[i] = (unsigned char) bytes[i]; \
+ chars[i] = 0;
+
+void
+js_InflateStringToBuffer(jschar *chars, const char *bytes, size_t length)
+{
+ size_t i;
+
+ INFLATE_STRING_BODY
+}
+
+jschar *
+js_InflateString(JSContext *cx, const char *bytes, size_t length)
+{
+ jschar *chars;
+ size_t i;
+
+ chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
+ if (!chars)
+ return NULL;
+
+ INFLATE_STRING_BODY
+
+ return chars;
+}
+
+/*
+ * May be called with null cx by js_GetStringBytes, see below.
+ */
+char *
+js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
+{
+ size_t i, size;
+ char *bytes;
+
+ size = (length + 1) * sizeof(char);
+ bytes = (char *) (cx ? JS_malloc(cx, size) : malloc(size));
+ if (!bytes)
+ return NULL;
+ for (i = 0; i < length; i++)
+ bytes[i] = (char) chars[i];
+ bytes[i] = 0;
+ return bytes;
+}
+
+static JSHashTable *
+GetDeflatedStringCache(void)
+{
+ JSHashTable *cache;
+
+ cache = deflated_string_cache;
+ if (!cache) {
+ cache = JS_NewHashTable(8, js_hash_string_pointer,
+ JS_CompareValues, JS_CompareValues,
+ NULL, NULL);
+ deflated_string_cache = cache;
+ }
+ return cache;
+}
+
+JSBool
+js_SetStringBytes(JSString *str, char *bytes, size_t length)
+{
+ JSHashTable *cache;
+ JSBool ok;
+ JSHashNumber hash;
+ JSHashEntry **hep;
+
+ JS_ACQUIRE_LOCK(deflated_string_cache_lock);
+
+ cache = GetDeflatedStringCache();
+ if (!cache) {
+ ok = JS_FALSE;
+ } else {
+ hash = js_hash_string_pointer(str);
+ hep = JS_HashTableRawLookup(cache, hash, str);
+ JS_ASSERT(*hep == NULL);
+ ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL;
+#ifdef DEBUG
+ if (ok)
+ deflated_string_cache_bytes += length;
+#endif
+ }
+
+ JS_RELEASE_LOCK(deflated_string_cache_lock);
+ return ok;
+}
+
+char *
+js_GetStringBytes(JSString *str)
+{
+ JSHashTable *cache;
+ char *bytes;
+ JSHashNumber hash;
+ JSHashEntry *he, **hep;
+
+ JS_ACQUIRE_LOCK(deflated_string_cache_lock);
+
+ cache = GetDeflatedStringCache();
+ if (!cache) {
+ bytes = NULL;
+ } else {
+ hash = js_hash_string_pointer(str);
+ hep = JS_HashTableRawLookup(cache, hash, str);
+ he = *hep;
+ if (he) {
+ bytes = (char *) he->value;
+
+ /* Try to catch failure to JS_ShutDown between runtime epochs. */
+ JS_ASSERT((*bytes == '\0' && JSSTRING_LENGTH(str) == 0) ||
+ *bytes == (char) JSSTRING_CHARS(str)[0]);
+ } else {
+ bytes = js_DeflateString(NULL, JSSTRING_CHARS(str),
+ JSSTRING_LENGTH(str));
+ if (bytes) {
+ if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
+#ifdef DEBUG
+ deflated_string_cache_bytes += JSSTRING_LENGTH(str);
+#endif
+ } else {
+ free(bytes);
+ bytes = NULL;
+ }
+ }
+ }
+ }
+
+ JS_RELEASE_LOCK(deflated_string_cache_lock);
+ return bytes;
+}
+
+/*
+ * From java.lang.Character.java:
+ *
+ * The character properties are currently encoded into 32 bits in the
+ * following manner:
+ *
+ * 10 bits signed offset used for converting case
+ * 1 bit if 1, adding the signed offset converts the character to
+ * lowercase
+ * 1 bit if 1, subtracting the signed offset converts the character to
+ * uppercase
+ * 1 bit if 1, character has a titlecase equivalent (possibly itself)
+ * 3 bits 0 may not be part of an identifier
+ * 1 ignorable control; may continue a Unicode identifier or JS
+ * identifier
+ * 2 may continue a JS identifier but not a Unicode identifier
+ * (unused)
+ * 3 may continue a Unicode identifier or JS identifier
+ * 4 is a JS whitespace character
+ * 5 may start or continue a JS identifier;
+ * may continue but not start a Unicode identifier (_)
+ * 6 may start or continue a JS identifier but not a Unicode
+ * identifier ($)
+ * 7 may start or continue a Unicode identifier or JS identifier
+ * Thus:
+ * 5, 6, 7 may start a JS identifier
+ * 1, 2, 3, 5, 6, 7 may continue a JS identifier
+ * 7 may start a Unicode identifier
+ * 1, 3, 5, 7 may continue a Unicode identifier
+ * 1 is ignorable within an identifier
+ * 4 is JS whitespace
+ * 2 bits 0 this character has no numeric property
+ * 1 adding the digit offset to the character code and then
+ * masking with 0x1F will produce the desired numeric value
+ * 2 this character has a "strange" numeric value
+ * 3 a JS supradecimal digit: adding the digit offset to the
+ * character code, then masking with 0x1F, then adding 10
+ * will produce the desired numeric value
+ * 5 bits digit offset
+ * 4 bits reserved for future use
+ * 5 bits character type
+ */
+
+/* The X table has 1024 entries for a total of 1024 bytes. */
+
+const uint8 js_X[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */
+ 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */
+ 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */
+ 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */
+ 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */
+ 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */
+ 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */
+ 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */
+ 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */
+ 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */
+ 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */
+ 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */
+ 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */
+ 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */
+ 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */
+ 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */
+ 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */
+ 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */
+ 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */
+ 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */
+104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */
+104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */
+104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */
+104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */
+105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */
+105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */
+106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */
+ 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */
+115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */
+};
+
+/* The Y table has 7808 entries for a total of 7808 bytes. */
+
+const uint8 js_Y[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
+ 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
+ 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */
+ 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */
+ 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */
+ 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */
+ 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */
+ 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
+ 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
+ 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */
+ 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */
+ 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
+ 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
+ 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
+ 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */
+ 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */
+ 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */
+ 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */
+ 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
+ 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
+ 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */
+ 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */
+ 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
+ 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
+ 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */
+ 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
+ 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */
+ 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */
+ 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */
+ 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
+ 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */
+ 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */
+ 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */
+ 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */
+ 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */
+ 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */
+ 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */
+ 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */
+ 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */
+ 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */
+ 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */
+ 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */
+ 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
+ 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */
+ 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
+ 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */
+ 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */
+ 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */
+ 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */
+ 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */
+ 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */
+ 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */
+ 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */
+ 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */
+ 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
+ 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
+ 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */
+ 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */
+ 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */
+ 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
+ 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */
+ 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
+ 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */
+ 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */
+ 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
+ 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
+ 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
+ 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */
+ 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */
+ 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */
+ 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */
+ 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */
+ 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */
+ 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */
+ 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */
+ 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */
+ 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */
+ 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */
+ 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */
+ 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */
+ 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */
+ 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */
+ 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */
+ 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */
+ 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */
+ 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
+ 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
+ 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
+ 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
+ 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
+ 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
+ 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
+ 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
+ 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */
+ 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
+ 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
+ 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */
+ 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
+ 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */
+ 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */
+ 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
+ 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */
+ 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */
+ 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
+ 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
+ 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */
+ 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */
+ 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */
+ 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
+ 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
+ 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
+ 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */
+ 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */
+ 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
+ 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
+ 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */
+ 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
+ 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */
+ 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
+ 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
+ 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */
+ 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
+ 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */
+ 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */
+ 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */
+ 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */
+ 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */
+ 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */
+ 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
+ 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */
+ 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */
+ 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */
+ 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */
+ 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */
+ 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */
+ 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */
+ 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
+ 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
+ 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */
+ 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */
+ 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */
+ 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */
+ 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */
+ 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */
+ 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */
+ 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */
+ 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */
+ 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */
+ 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */
+ 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */
+ 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */
+ 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */
+ 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */
+ 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */
+ 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */
+ 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */
+ 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */
+ 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */
+ 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */
+ 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */
+ 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */
+ 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */
+ 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
+ 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */
+ 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */
+ 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
+ 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */
+ 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */
+ 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */
+ 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */
+ 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */
+ 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */
+ 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */
+ 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
+ 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
+ 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */
+ 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */
+ 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */
+ 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */
+ 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */
+ 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */
+ 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */
+ 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */
+ 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */
+ 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */
+ 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */
+ 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */
+ 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
+ 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */
+ 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */
+ 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */
+ 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
+ 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */
+ 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */
+ 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */
+ 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */
+ 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
+ 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */
+ 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
+ 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */
+ 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
+ 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */
+ 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */
+ 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */
+ 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */
+ 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
+ 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
+ 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */
+ 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
+ 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */
+ 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */
+ 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */
+ 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */
+ 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */
+ 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */
+ 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
+ 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */
+ 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
+ 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
+ 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */
+ 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */
+ 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */
+ 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
+ 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */
+ 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
+ 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
+ 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */
+ 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */
+ 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */
+ 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */
+ 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */
+ 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */
+ 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
+ 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */
+ 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */
+ 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */
+ 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */
+ 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */
+ 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */
+ 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */
+ 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */
+ 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */
+ 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */
+ 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */
+ 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
+ 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */
+ 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */
+ 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */
+ 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */
+ 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */
+ 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */
+ 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */
+ 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
+ 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
+ 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */
+ 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */
+ 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */
+ 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */
+ 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */
+ 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */
+ 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */
+ 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */
+ 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
+ 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
+ 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
+ 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
+ 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
+ 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
+ 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */
+ 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
+ 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
+ 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
+ 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
+ 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */
+ 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
+ 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
+ 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
+ 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
+ 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */
+ 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
+ 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
+ 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */
+ 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
+ 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
+ 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */
+ 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */
+ 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
+ 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
+ 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
+ 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
+ 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */
+ 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */
+ 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */
+ 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */
+ 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */
+ 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */
+ 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */
+ 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */
+ 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
+ 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
+ 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
+ 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
+ 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
+ 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
+ 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */
+ 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */
+ 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */
+ 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */
+ 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */
+ 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */
+ 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */
+ 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */
+ 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */
+102, 102, 103, 103, 96, 11, 11, 46, /* 66 */
+ 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */
+ 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */
+ 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */
+ 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */
+ 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
+105, 106, 104, 104, 104, 104, 104, 46, /* 67 */
+ 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
+ 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */
+ 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
+ 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */
+ 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */
+ 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */
+107, 107, 107, 107, 107, 107, 107, 107, /* 69 */
+107, 107, 7, 7, 7, 5, 6, 46, /* 69 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
+ 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */
+ 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
+ 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */
+ 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */
+ 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
+ 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */
+ 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */
+ 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */
+ 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */
+ 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */
+ 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */
+ 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */
+ 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
+ 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */
+ 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */
+109, 109, 109, 109, 109, 109, 109, 109, /* 72 */
+109, 109, 109, 109, 110, 110, 110, 110, /* 72 */
+111, 111, 111, 111, 111, 111, 111, 111, /* 72 */
+111, 111, 111, 111, 112, 112, 112, 112, /* 72 */
+113, 113, 113, 46, 46, 46, 46, 46, /* 73 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */
+ 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
+ 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
+ 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
+ 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
+ 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */
+ 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */
+ 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
+ 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */
+ 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
+ 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
+ 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */
+ 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
+114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
+114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
+114, 114, 114, 114, 82, 82, 82, 82, /* 80 */
+ 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */
+ 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */
+115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
+115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
+115, 115, 115, 115, 15, 15, 15, 15, /* 81 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
+ 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */
+116, 116, 116, 116, 116, 116, 116, 116, /* 81 */
+116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
+116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
+117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
+117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
+117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
+117, 117, 118, 46, 46, 46, 46, 46, /* 82 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
+ 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
+ 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */
+ 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
+ 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */
+ 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
+ 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */
+ 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */
+ 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */
+ 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */
+ 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */
+ 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */
+119, 119, 119, 119, 119, 119, 119, 119, /* 88 */
+114, 114, 114, 114, 114, 114, 114, 114, /* 89 */
+114, 114, 83, 83, 83, 83, 83, 83, /* 89 */
+ 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
+ 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */
+ 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */
+ 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */
+ 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */
+ 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */
+ 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */
+ 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */
+121, 121, 60, 60, 60, 60, 60, 60, /* 90 */
+ 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */
+ 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */
+ 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
+ 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */
+ 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */
+ 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
+ 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */
+ 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
+ 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */
+ 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */
+ 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */
+ 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
+ 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */
+ 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */
+ 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
+ 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
+ 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */
+114, 114, 114, 114, 114, 114, 114, 114, /* 98 */
+114, 114, 15, 15, 15, 15, 15, 15, /* 98 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
+ 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
+ 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
+ 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
+ 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */
+ 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
+ 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
+ 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
+ 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
+ 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
+ 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
+ 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */
+ 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */
+ 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */
+ 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */
+ 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */
+ 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */
+ 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
+ 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
+ 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
+ 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
+ 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
+ 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
+ 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
+ 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */
+ 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */
+ 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */
+ 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */
+ 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */
+ 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */
+ 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */
+ 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */
+ 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
+ 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */
+ 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */
+ 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */
+ 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */
+ 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */
+ 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */
+ 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
+ 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
+ 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */
+ 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */
+ 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
+ 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
+ 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */
+ 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
+ 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
+ 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
+ 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
+ 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */
+ 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
+ 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
+ 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
+ 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */
+ 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */
+ 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */
+ 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */
+ 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */
+};
+
+/* The A table has 124 entries for a total of 496 bytes. */
+
+const uint32 js_A[] = {
+0x0001000F, /* 0 Cc, ignorable */
+0x0004000F, /* 1 Cc, whitespace */
+0x0004000C, /* 2 Zs, whitespace */
+0x00000018, /* 3 Po */
+0x0006001A, /* 4 Sc, currency */
+0x00000015, /* 5 Ps */
+0x00000016, /* 6 Pe */
+0x00000019, /* 7 Sm */
+0x00000014, /* 8 Pd */
+0x00036009, /* 9 Nd, identifier part, decimal 16 */
+0x0827FE01, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */
+0x0000001B, /* 11 Sk */
+0x00050017, /* 12 Pc, underscore */
+0x0817FE02, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
+0x0000000C, /* 14 Zs */
+0x0000001C, /* 15 So */
+0x00070002, /* 16 Ll, identifier start */
+0x0000600B, /* 17 No, decimal 16 */
+0x0000500B, /* 18 No, decimal 8 */
+0x0000800B, /* 19 No, strange */
+0x08270001, /* 20 Lu, hasLower (add 32), identifier start */
+0x08170002, /* 21 Ll, hasUpper (subtract 32), identifier start */
+0xE1D70002, /* 22 Ll, hasUpper (subtract -121), identifier start */
+0x00670001, /* 23 Lu, hasLower (add 1), identifier start */
+0x00570002, /* 24 Ll, hasUpper (subtract 1), identifier start */
+0xCE670001, /* 25 Lu, hasLower (add -199), identifier start */
+0x3A170002, /* 26 Ll, hasUpper (subtract 232), identifier start */
+0xE1E70001, /* 27 Lu, hasLower (add -121), identifier start */
+0x4B170002, /* 28 Ll, hasUpper (subtract 300), identifier start */
+0x34A70001, /* 29 Lu, hasLower (add 210), identifier start */
+0x33A70001, /* 30 Lu, hasLower (add 206), identifier start */
+0x33670001, /* 31 Lu, hasLower (add 205), identifier start */
+0x32A70001, /* 32 Lu, hasLower (add 202), identifier start */
+0x32E70001, /* 33 Lu, hasLower (add 203), identifier start */
+0x33E70001, /* 34 Lu, hasLower (add 207), identifier start */
+0x34E70001, /* 35 Lu, hasLower (add 211), identifier start */
+0x34670001, /* 36 Lu, hasLower (add 209), identifier start */
+0x35670001, /* 37 Lu, hasLower (add 213), identifier start */
+0x00070001, /* 38 Lu, identifier start */
+0x36A70001, /* 39 Lu, hasLower (add 218), identifier start */
+0x00070005, /* 40 Lo, identifier start */
+0x36670001, /* 41 Lu, hasLower (add 217), identifier start */
+0x36E70001, /* 42 Lu, hasLower (add 219), identifier start */
+0x00AF0001, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */
+0x007F0003, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
+0x009F0002, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */
+0x00000000, /* 46 unassigned */
+0x34970002, /* 47 Ll, hasUpper (subtract 210), identifier start */
+0x33970002, /* 48 Ll, hasUpper (subtract 206), identifier start */
+0x33570002, /* 49 Ll, hasUpper (subtract 205), identifier start */
+0x32970002, /* 50 Ll, hasUpper (subtract 202), identifier start */
+0x32D70002, /* 51 Ll, hasUpper (subtract 203), identifier start */
+0x33D70002, /* 52 Ll, hasUpper (subtract 207), identifier start */
+0x34570002, /* 53 Ll, hasUpper (subtract 209), identifier start */
+0x34D70002, /* 54 Ll, hasUpper (subtract 211), identifier start */
+0x35570002, /* 55 Ll, hasUpper (subtract 213), identifier start */
+0x36970002, /* 56 Ll, hasUpper (subtract 218), identifier start */
+0x36570002, /* 57 Ll, hasUpper (subtract 217), identifier start */
+0x36D70002, /* 58 Ll, hasUpper (subtract 219), identifier start */
+0x00070004, /* 59 Lm, identifier start */
+0x00030006, /* 60 Mn, identifier part */
+0x09A70001, /* 61 Lu, hasLower (add 38), identifier start */
+0x09670001, /* 62 Lu, hasLower (add 37), identifier start */
+0x10270001, /* 63 Lu, hasLower (add 64), identifier start */
+0x0FE70001, /* 64 Lu, hasLower (add 63), identifier start */
+0x09970002, /* 65 Ll, hasUpper (subtract 38), identifier start */
+0x09570002, /* 66 Ll, hasUpper (subtract 37), identifier start */
+0x10170002, /* 67 Ll, hasUpper (subtract 64), identifier start */
+0x0FD70002, /* 68 Ll, hasUpper (subtract 63), identifier start */
+0x0F970002, /* 69 Ll, hasUpper (subtract 62), identifier start */
+0x0E570002, /* 70 Ll, hasUpper (subtract 57), identifier start */
+0x0BD70002, /* 71 Ll, hasUpper (subtract 47), identifier start */
+0x0D970002, /* 72 Ll, hasUpper (subtract 54), identifier start */
+0x15970002, /* 73 Ll, hasUpper (subtract 86), identifier start */
+0x14170002, /* 74 Ll, hasUpper (subtract 80), identifier start */
+0x14270001, /* 75 Lu, hasLower (add 80), identifier start */
+0x0C270001, /* 76 Lu, hasLower (add 48), identifier start */
+0x0C170002, /* 77 Ll, hasUpper (subtract 48), identifier start */
+0x00034009, /* 78 Nd, identifier part, decimal 0 */
+0x00000007, /* 79 Me */
+0x00030008, /* 80 Mc, identifier part */
+0x00037409, /* 81 Nd, identifier part, decimal 26 */
+0x00005A0B, /* 82 No, decimal 13 */
+0x00006E0B, /* 83 No, decimal 23 */
+0x0000740B, /* 84 No, decimal 26 */
+0x0000000B, /* 85 No */
+0xFE170002, /* 86 Ll, hasUpper (subtract -8), identifier start */
+0xFE270001, /* 87 Lu, hasLower (add -8), identifier start */
+0xED970002, /* 88 Ll, hasUpper (subtract -74), identifier start */
+0xEA970002, /* 89 Ll, hasUpper (subtract -86), identifier start */
+0xE7170002, /* 90 Ll, hasUpper (subtract -100), identifier start */
+0xE0170002, /* 91 Ll, hasUpper (subtract -128), identifier start */
+0xE4170002, /* 92 Ll, hasUpper (subtract -112), identifier start */
+0xE0970002, /* 93 Ll, hasUpper (subtract -126), identifier start */
+0xFDD70002, /* 94 Ll, hasUpper (subtract -9), identifier start */
+0xEDA70001, /* 95 Lu, hasLower (add -74), identifier start */
+0xFDE70001, /* 96 Lu, hasLower (add -9), identifier start */
+0xEAA70001, /* 97 Lu, hasLower (add -86), identifier start */
+0xE7270001, /* 98 Lu, hasLower (add -100), identifier start */
+0xFE570002, /* 99 Ll, hasUpper (subtract -7), identifier start */
+0xE4270001, /* 100 Lu, hasLower (add -112), identifier start */
+0xFE670001, /* 101 Lu, hasLower (add -7), identifier start */
+0xE0270001, /* 102 Lu, hasLower (add -128), identifier start */
+0xE0A70001, /* 103 Lu, hasLower (add -126), identifier start */
+0x00010010, /* 104 Cf, ignorable */
+0x0004000D, /* 105 Zl, whitespace */
+0x0004000E, /* 106 Zp, whitespace */
+0x0000400B, /* 107 No, decimal 0 */
+0x0000440B, /* 108 No, decimal 2 */
+0x0427420A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */
+0x0427800A, /* 110 Nl, hasLower (add 16), identifier start, strange */
+0x0417620A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */
+0x0417800A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */
+0x0007800A, /* 113 Nl, identifier start, strange */
+0x0000420B, /* 114 No, decimal 1 */
+0x0000720B, /* 115 No, decimal 25 */
+0x06A0001C, /* 116 So, hasLower (add 26) */
+0x0690001C, /* 117 So, hasUpper (subtract 26) */
+0x00006C0B, /* 118 No, decimal 22 */
+0x0000560B, /* 119 No, decimal 11 */
+0x0007720A, /* 120 Nl, identifier start, decimal 25 */
+0x0007400A, /* 121 Nl, identifier start, decimal 0 */
+0x00000013, /* 122 Cs */
+0x00000012 /* 123 Co */
+};
+
+const jschar js_uriReservedPlusPound_ucstr[] =
+ {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
+const jschar js_uriUnescaped_ucstr[] =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
+
+#define URI_CHUNK 64U
+
+/* Concatenate jschars onto an unshared/newborn JSString. */
+static JSBool
+AddCharsToURI(JSContext *cx, JSString *str, const jschar *chars, size_t length)
+{
+ size_t total;
+
+ JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
+ total = str->length + length + 1;
+ if (!str->chars ||
+ JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(str->length + 1, URI_CHUNK)) {
+ total = JS_ROUNDUP(total, URI_CHUNK);
+ str->chars = JS_realloc(cx, str->chars, total * sizeof(jschar));
+ if (!str->chars)
+ return JS_FALSE;
+ }
+ js_strncpy(str->chars + str->length, chars, length);
+ str->length += length;
+ str->chars[str->length] = 0;
+ return JS_TRUE;
+}
+
+/*
+ * ECMA 3, 15.1.3 URI Handling Function Properties
+ *
+ * The following are implementations of the algorithms
+ * given in the ECMA specification for the hidden functions
+ * 'Encode' and 'Decode'.
+ */
+static JSBool
+Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
+ const jschar *unescapedSet2, jsval *rval)
+{
+ size_t length, j, k, L;
+ jschar *chars, C, C2;
+ uint32 V;
+ uint8 utf8buf[6];
+ jschar hexBuf[4];
+ static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
+ JSString *R;
+
+ R = js_NewString(cx, NULL, 0, 0);
+ if (!R)
+ return JS_FALSE;
+
+ hexBuf[0] = '%';
+ hexBuf[3] = 0;
+ chars = JSSTRING_CHARS(str);
+ length = JSSTRING_LENGTH(str);
+ for (k = 0; k < length; k++) {
+ C = chars[k];
+ if (js_strchr(unescapedSet, C) ||
+ (unescapedSet2 && js_strchr(unescapedSet2, C))) {
+ if (!AddCharsToURI(cx, R, &C, 1))
+ return JS_FALSE;
+ } else {
+ if ((C >= 0xDC00) && (C <= 0xDFFF)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_URI, NULL);
+ return JS_FALSE;
+ }
+ if (C < 0xD800 || C > 0xDBFF) {
+ V = C;
+ } else {
+ k++;
+ if (k == length) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_URI, NULL);
+ return JS_FALSE;
+ }
+ C2 = chars[k];
+ if ((C2 < 0xDC00) || (C2 > 0xDFFF)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_URI, NULL);
+ return JS_FALSE;
+ }
+ V = ((C - 0xD800) << 10) + (C2 - 0xDC00) + 0x10000;
+ }
+ L = OneUcs4ToUtf8Char(utf8buf, V);
+ for (j = 0; j < L; j++) {
+ hexBuf[1] = HexDigits[utf8buf[j] >> 4];
+ hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
+ if (!AddCharsToURI(cx, R, hexBuf, 3))
+ return JS_FALSE;
+ }
+ }
+ }
+
+ /*
+ * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
+ * don't worry about that case here. Worst case, R hangs onto URI_CHUNK-1
+ * more jschars than it needs.
+ */
+ chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
+ if (chars)
+ R->chars = chars;
+ *rval = STRING_TO_JSVAL(R);
+ return JS_TRUE;
+}
+
+static JSBool
+Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
+{
+ size_t length, start, k;
+ jschar *chars, C, H;
+ uint32 V;
+ jsuint B;
+ uint8 octets[6];
+ JSString *R;
+ intN j, n;
+
+ R = js_NewString(cx, NULL, 0, 0);
+ if (!R)
+ return JS_FALSE;
+
+ chars = JSSTRING_CHARS(str);
+ length = JSSTRING_LENGTH(str);
+ for (k = 0; k < length; k++) {
+ C = chars[k];
+ if (C == '%') {
+ start = k;
+ if ((k + 2) >= length)
+ goto bad;
+ if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
+ goto bad;
+ B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
+ k += 2;
+ if (!(B & 0x80)) {
+ C = (jschar)B;
+ } else {
+ n = 1;
+ while (B & (0x80 >> n))
+ n++;
+ if (n == 1 || n > 6)
+ goto bad;
+ octets[0] = (uint8)B;
+ if (k + 3 * (n - 1) >= length)
+ goto bad;
+ for (j = 1; j < n; j++) {
+ k++;
+ if (chars[k] != '%')
+ goto bad;
+ if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
+ goto bad;
+ B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
+ if ((B & 0xC0) != 0x80)
+ goto bad;
+ k += 2;
+ octets[j] = (char)B;
+ }
+ V = Utf8ToOneUcs4Char(octets, n);
+ if (V >= 0x10000) {
+ V -= 0x10000;
+ if (V > 0xFFFFF)
+ goto bad;
+ C = (jschar)((V & 0x3FF) + 0xDC00);
+ H = (jschar)((V >> 10) + 0xD800);
+ if (!AddCharsToURI(cx, R, &H, 1))
+ return JS_FALSE;
+ } else {
+ C = (jschar)V;
+ }
+ }
+ if (js_strchr(reservedSet, C)) {
+ if (!AddCharsToURI(cx, R, &chars[start], (k - start + 1)))
+ return JS_FALSE;
+ } else {
+ if (!AddCharsToURI(cx, R, &C, 1))
+ return JS_FALSE;
+ }
+ } else {
+ if (!AddCharsToURI(cx, R, &C, 1))
+ return JS_FALSE;
+ }
+ }
+
+ /*
+ * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
+ * don't worry about that case here. Worst case, R hangs onto URI_CHUNK-1
+ * more jschars than it needs.
+ */
+ chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
+ if (chars)
+ R->chars = chars;
+ *rval = STRING_TO_JSVAL(R);
+ return JS_TRUE;
+
+bad:
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
+ return JS_FALSE;
+}
+
+static JSBool
+str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ return Decode(cx, str, js_uriReservedPlusPound_ucstr, rval);
+}
+
+static JSBool
+str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ return Decode(cx, str, js_empty_ucstr, rval);
+}
+
+static JSBool
+str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
+ rval);
+}
+
+static JSBool
+str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+
+ str = js_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ return Encode(cx, str, js_uriUnescaped_ucstr, NULL, rval);
+}
+
+/*
+ * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
+ * least 6 bytes long. Return the number of UTF-8 bytes of data written.
+ */
+static int
+OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
+{
+ int utf8Length = 1;
+
+ JS_ASSERT(ucs4Char <= 0x7FFFFFFF);
+ if (ucs4Char < 0x80) {
+ *utf8Buffer = (uint8)ucs4Char;
+ } else {
+ int i;
+ uint32 a = ucs4Char >> 11;
+ utf8Length = 2;
+ while (a) {
+ a >>= 5;
+ utf8Length++;
+ }
+ i = utf8Length;
+ while (--i) {
+ utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
+ ucs4Char >>= 6;
+ }
+ *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
+ }
+ return utf8Length;
+}
+
+/*
+ * Convert a utf8 character sequence into a UCS-4 character and return that
+ * character. It is assumed that the caller already checked that the sequence
+ * is valid.
+ */
+static uint32
+Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
+{
+ uint32 ucs4Char;
+ uint32 minucs4Char;
+ /* from Unicode 3.1, non-shortest form is illegal */
+ static const uint32 minucs4Table[] = {
+ 0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
+ };
+
+ JS_ASSERT(utf8Length >= 1 && utf8Length <= 6);
+ if (utf8Length == 1) {
+ ucs4Char = *utf8Buffer;
+ JS_ASSERT(!(ucs4Char & 0x80));
+ } else {
+ JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
+ (0x100 - (1 << (8-utf8Length))));
+ ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
+ minucs4Char = minucs4Table[utf8Length-2];
+ while (--utf8Length) {
+ JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
+ ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
+ }
+ if (ucs4Char < minucs4Char ||
+ ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
+ ucs4Char = 0xFFFD;
+ }
+ }
+ return ucs4Char;
+}
diff --git a/src/dom/js/jsstr.h b/src/dom/js/jsstr.h
new file mode 100644
index 000000000..94ebe97b9
--- /dev/null
+++ b/src/dom/js/jsstr.h
@@ -0,0 +1,439 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsstr_h___
+#define jsstr_h___
+/*
+ * JS string type implementation.
+ *
+ * A JS string is a counted array of unicode characters. To support handoff
+ * of API client memory, the chars are allocated separately from the length,
+ * necessitating a pointer after the count, to form a separately allocated
+ * string descriptor. String descriptors are GC'ed, while their chars are
+ * allocated from the malloc heap.
+ *
+ * When a string is treated as an object (by following it with . or []), the
+ * runtime wraps it with a JSObject whose valueOf method returns the unwrapped
+ * string descriptor.
+ */
+#include <ctype.h>
+#include "jspubtd.h"
+#include "jsprvtd.h"
+#include "jshash.h"
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * The original GC-thing "string" type, a flat character string owned by its
+ * GC-thing descriptor. The chars member points to a vector having byte size
+ * (length + 1) * sizeof(jschar), terminated at index length by a zero jschar.
+ * The terminator is purely a backstop, in case the chars pointer flows out to
+ * native code that requires \u0000 termination.
+ *
+ * NB: Always use the JSSTRING_LENGTH and JSSTRING_CHARS accessor macros,
+ * unless you guard str->member uses with !JSSTRING_IS_DEPENDENT(str).
+ */
+struct JSString {
+ size_t length;
+ jschar *chars;
+};
+
+/*
+ * Overlay structure for a string that depends on another string's characters.
+ * Distinguished by the JSSTRFLAG_DEPENDENT bit being set in length. The base
+ * member may point to another dependent string if JSSTRING_CHARS has not been
+ * called yet. The length chars in a dependent string are stored starting at
+ * base->chars + start, and are not necessarily zero-terminated. If start is
+ * 0, it is not stored, length is a full size_t (minus the JSSTRFLAG_* bits in
+ * the high two positions), and the JSSTRFLAG_PREFIX flag is set.
+ */
+struct JSDependentString {
+ size_t length;
+ JSString *base;
+};
+
+/* Definitions for flags stored in the high order bits of JSString.length. */
+#define JSSTRFLAG_BITS 2
+#define JSSTRFLAG_SHIFT(flg) ((size_t)(flg) << JSSTRING_LENGTH_BITS)
+#define JSSTRFLAG_MASK JSSTRFLAG_SHIFT(JS_BITMASK(JSSTRFLAG_BITS))
+#define JSSTRFLAG_DEPENDENT JSSTRFLAG_SHIFT(1)
+#define JSSTRFLAG_PREFIX JSSTRFLAG_SHIFT(2)
+
+/* Universal JSString type inquiry and accessor macros. */
+#define JSSTRING_BIT(n) ((size_t)1 << (n))
+#define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1)
+#define JSSTRING_HAS_FLAG(str,flg) ((str)->length & (flg))
+#define JSSTRING_IS_DEPENDENT(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_DEPENDENT)
+#define JSSTRING_IS_PREFIX(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_PREFIX)
+#define JSSTRING_CHARS(str) (JSSTRING_IS_DEPENDENT(str) \
+ ? JSSTRDEP_CHARS(str) \
+ : (str)->chars)
+#define JSSTRING_LENGTH(str) (JSSTRING_IS_DEPENDENT(str) \
+ ? JSSTRDEP_LENGTH(str) \
+ : (str)->length)
+#define JSSTRING_LENGTH_BITS (sizeof(size_t) * JS_BITS_PER_BYTE \
+ - JSSTRFLAG_BITS)
+#define JSSTRING_LENGTH_MASK JSSTRING_BITMASK(JSSTRING_LENGTH_BITS)
+
+/* Specific JSDependentString shift/mask accessor and mutator macros. */
+#define JSSTRDEP_START_BITS (JSSTRING_LENGTH_BITS-JSSTRDEP_LENGTH_BITS)
+#define JSSTRDEP_START_SHIFT JSSTRDEP_LENGTH_BITS
+#define JSSTRDEP_START_MASK JSSTRING_BITMASK(JSSTRDEP_START_BITS)
+#define JSSTRDEP_LENGTH_BITS (JSSTRING_LENGTH_BITS / 2)
+#define JSSTRDEP_LENGTH_MASK JSSTRING_BITMASK(JSSTRDEP_LENGTH_BITS)
+
+#define JSSTRDEP(str) ((JSDependentString *)(str))
+#define JSSTRDEP_START(str) (JSSTRING_IS_PREFIX(str) ? 0 \
+ : ((JSSTRDEP(str)->length \
+ >> JSSTRDEP_START_SHIFT) \
+ & JSSTRDEP_START_MASK))
+#define JSSTRDEP_LENGTH(str) (JSSTRDEP(str)->length \
+ & (JSSTRING_IS_PREFIX(str) \
+ ? JSSTRING_LENGTH_MASK \
+ : JSSTRDEP_LENGTH_MASK))
+
+#define JSSTRDEP_SET_START_AND_LENGTH(str,off,len) \
+ (JSSTRDEP(str)->length = JSSTRFLAG_DEPENDENT \
+ | ((off) << JSSTRDEP_START_SHIFT) \
+ | (len))
+#define JSPREFIX_SET_LENGTH(str,len) \
+ (JSSTRDEP(str)->length = JSSTRFLAG_DEPENDENT | JSSTRFLAG_PREFIX | (len))
+
+#define JSSTRDEP_BASE(str) (JSSTRDEP(str)->base)
+#define JSSTRDEP_SET_BASE(str,bstr) (JSSTRDEP(str)->base = (bstr))
+#define JSPREFIX_BASE(str) JSSTRDEP_BASE(str)
+#define JSPREFIX_SET_BASE(str,bstr) JSSTRDEP_SET_BASE(str,bstr)
+
+#define JSSTRDEP_CHARS(str) \
+ (JSSTRING_IS_DEPENDENT(JSSTRDEP_BASE(str)) \
+ ? js_GetDependentStringChars(str) \
+ : JSSTRDEP_BASE(str)->chars + JSSTRDEP_START(str))
+
+extern size_t
+js_MinimizeDependentStrings(JSString *str, int level, JSString **basep);
+
+extern jschar *
+js_GetDependentStringChars(JSString *str);
+
+extern jschar *
+js_GetStringChars(JSString *str);
+
+extern JSString *
+js_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
+
+extern const jschar *
+js_UndependString(JSContext *cx, JSString *str);
+
+struct JSSubString {
+ size_t length;
+ const jschar *chars;
+};
+
+extern jschar js_empty_ucstr[];
+extern JSSubString js_EmptySubString;
+
+/* Unicode character attribute lookup tables. */
+extern const uint8 js_X[];
+extern const uint8 js_Y[];
+extern const uint32 js_A[];
+
+/* Enumerated Unicode general category types. */
+typedef enum JSCharType {
+ JSCT_UNASSIGNED = 0,
+ JSCT_UPPERCASE_LETTER = 1,
+ JSCT_LOWERCASE_LETTER = 2,
+ JSCT_TITLECASE_LETTER = 3,
+ JSCT_MODIFIER_LETTER = 4,
+ JSCT_OTHER_LETTER = 5,
+ JSCT_NON_SPACING_MARK = 6,
+ JSCT_ENCLOSING_MARK = 7,
+ JSCT_COMBINING_SPACING_MARK = 8,
+ JSCT_DECIMAL_DIGIT_NUMBER = 9,
+ JSCT_LETTER_NUMBER = 10,
+ JSCT_OTHER_NUMBER = 11,
+ JSCT_SPACE_SEPARATOR = 12,
+ JSCT_LINE_SEPARATOR = 13,
+ JSCT_PARAGRAPH_SEPARATOR = 14,
+ JSCT_CONTROL = 15,
+ JSCT_FORMAT = 16,
+ JSCT_PRIVATE_USE = 18,
+ JSCT_SURROGATE = 19,
+ JSCT_DASH_PUNCTUATION = 20,
+ JSCT_START_PUNCTUATION = 21,
+ JSCT_END_PUNCTUATION = 22,
+ JSCT_CONNECTOR_PUNCTUATION = 23,
+ JSCT_OTHER_PUNCTUATION = 24,
+ JSCT_MATH_SYMBOL = 25,
+ JSCT_CURRENCY_SYMBOL = 26,
+ JSCT_MODIFIER_SYMBOL = 27,
+ JSCT_OTHER_SYMBOL = 28
+} JSCharType;
+
+/* Character classifying and mapping macros, based on java.lang.Character. */
+#define JS_CCODE(c) (js_A[js_Y[(js_X[(uint16)(c)>>6]<<6)|((c)&0x3F)]])
+#define JS_CTYPE(c) (JS_CCODE(c) & 0x1F)
+
+#define JS_ISALPHA(c) ((((1 << JSCT_UPPERCASE_LETTER) | \
+ (1 << JSCT_LOWERCASE_LETTER) | \
+ (1 << JSCT_TITLECASE_LETTER) | \
+ (1 << JSCT_MODIFIER_LETTER) | \
+ (1 << JSCT_OTHER_LETTER)) \
+ >> JS_CTYPE(c)) & 1)
+
+#define JS_ISALNUM(c) ((((1 << JSCT_UPPERCASE_LETTER) | \
+ (1 << JSCT_LOWERCASE_LETTER) | \
+ (1 << JSCT_TITLECASE_LETTER) | \
+ (1 << JSCT_MODIFIER_LETTER) | \
+ (1 << JSCT_OTHER_LETTER) | \
+ (1 << JSCT_DECIMAL_DIGIT_NUMBER)) \
+ >> JS_CTYPE(c)) & 1)
+
+/* A unicode letter, suitable for use in an identifier. */
+#define JS_ISUC_LETTER(c) ((((1 << JSCT_UPPERCASE_LETTER) | \
+ (1 << JSCT_LOWERCASE_LETTER) | \
+ (1 << JSCT_TITLECASE_LETTER) | \
+ (1 << JSCT_MODIFIER_LETTER) | \
+ (1 << JSCT_OTHER_LETTER) | \
+ (1 << JSCT_LETTER_NUMBER)) \
+ >> JS_CTYPE(c)) & 1)
+
+/*
+* 'IdentifierPart' from ECMA grammar, is Unicode letter or
+* combining mark or digit or connector punctuation.
+*/
+#define JS_ISID_PART(c) ((((1 << JSCT_UPPERCASE_LETTER) | \
+ (1 << JSCT_LOWERCASE_LETTER) | \
+ (1 << JSCT_TITLECASE_LETTER) | \
+ (1 << JSCT_MODIFIER_LETTER) | \
+ (1 << JSCT_OTHER_LETTER) | \
+ (1 << JSCT_LETTER_NUMBER) | \
+ (1 << JSCT_NON_SPACING_MARK) | \
+ (1 << JSCT_COMBINING_SPACING_MARK) | \
+ (1 << JSCT_DECIMAL_DIGIT_NUMBER) | \
+ (1 << JSCT_CONNECTOR_PUNCTUATION)) \
+ >> JS_CTYPE(c)) & 1)
+
+/* Unicode control-format characters, ignored in input */
+#define JS_ISFORMAT(c) (((1 << JSCT_FORMAT) >> JS_CTYPE(c)) & 1)
+
+#define JS_ISWORD(c) (JS_ISALNUM(c) || (c) == '_')
+
+/* XXXbe unify on A/X/Y tbls, avoid ctype.h? */
+#define JS_ISIDENT_START(c) (JS_ISUC_LETTER(c) || (c) == '_' || (c) == '$')
+#define JS_ISIDENT(c) (JS_ISID_PART(c) || (c) == '_' || (c) == '$')
+
+#define JS_ISDIGIT(c) (JS_CTYPE(c) == JSCT_DECIMAL_DIGIT_NUMBER)
+
+/* XXXbe fs, etc. ? */
+#define JS_ISSPACE(c) ((JS_CCODE(c) & 0x00070000) == 0x00040000)
+#define JS_ISPRINT(c) ((c) < 128 && isprint(c))
+
+#define JS_ISUPPER(c) (JS_CTYPE(c) == JSCT_UPPERCASE_LETTER)
+#define JS_ISLOWER(c) (JS_CTYPE(c) == JSCT_LOWERCASE_LETTER)
+
+#define JS_TOUPPER(c) ((JS_CCODE(c) & 0x00100000) ? (c) - ((int32)JS_CCODE(c) >> 22) : (c))
+#define JS_TOLOWER(c) ((JS_CCODE(c) & 0x00200000) ? (c) + ((int32)JS_CCODE(c) >> 22) : (c))
+
+#define JS_TOCTRL(c) ((c) ^ 64) /* XXX unsafe! requires uppercase c */
+
+/* Shorthands for ASCII (7-bit) decimal and hex conversion. */
+#define JS7_ISDEC(c) ((c) < 128 && isdigit(c))
+#define JS7_UNDEC(c) ((c) - '0')
+#define JS7_ISHEX(c) ((c) < 128 && isxdigit(c))
+#define JS7_UNHEX(c) (uintN)(isdigit(c) ? (c) - '0' : 10 + tolower(c) - 'a')
+#define JS7_ISLET(c) ((c) < 128 && isalpha(c))
+
+/* Initialize truly global state associated with JS strings. */
+extern JSBool
+js_InitStringGlobals(void);
+
+extern void
+js_FreeStringGlobals(void);
+
+extern void
+js_PurgeDeflatedStringCache(JSString *str);
+
+/* Initialize per-runtime string state for the first context in the runtime. */
+extern JSBool
+js_InitRuntimeStringState(JSContext *cx);
+
+extern void
+js_FinishRuntimeStringState(JSContext *cx);
+
+/* Initialize the String class, returning its prototype object. */
+extern JSObject *
+js_InitStringClass(JSContext *cx, JSObject *obj);
+
+extern const char js_escape_str[];
+extern const char js_unescape_str[];
+extern const char js_uneval_str[];
+extern const char js_decodeURI_str[];
+extern const char js_encodeURI_str[];
+extern const char js_decodeURIComponent_str[];
+extern const char js_encodeURIComponent_str[];
+
+/* GC-allocate a string descriptor for the given malloc-allocated chars. */
+extern JSString *
+js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag);
+
+extern JSString *
+js_NewDependentString(JSContext *cx, JSString *base, size_t start,
+ size_t length, uintN gcflag);
+
+/* Copy a counted string and GC-allocate a descriptor for it. */
+extern JSString *
+js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n, uintN gcflag);
+
+/* Copy a C string and GC-allocate a descriptor for it. */
+extern JSString *
+js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag);
+
+/* Free the chars held by str when it is finalized by the GC. */
+extern void
+js_FinalizeString(JSContext *cx, JSString *str);
+
+extern void
+js_FinalizeStringRT(JSRuntime *rt, JSString *str);
+
+/* Wrap a string value in a String object. */
+extern JSObject *
+js_StringToObject(JSContext *cx, JSString *str);
+
+/*
+ * Convert a value to a string, returning null after reporting an error,
+ * otherwise returning a new string reference.
+ */
+extern JSString *
+js_ValueToString(JSContext *cx, jsval v);
+
+/*
+ * Convert a value to its source expression, returning null after reporting
+ * an error, otherwise returning a new string reference.
+ */
+extern JSString *
+js_ValueToSource(JSContext *cx, jsval v);
+
+#ifdef HT_ENUMERATE_NEXT /* XXX don't require jshash.h */
+/*
+ * Compute a hash function from str.
+ */
+extern JSHashNumber
+js_HashString(JSString *str);
+#endif
+
+/*
+ * Return less than, equal to, or greater than zero depending on whether
+ * str1 is less than, equal to, or greater than str2.
+ */
+extern intN
+js_CompareStrings(JSString *str1, JSString *str2);
+
+/*
+ * Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen.
+ * The patlen argument must be positive and no greater than BMH_PATLEN_MAX.
+ * The start argument tells where in text to begin the search.
+ *
+ * Return the index of pat in text, or -1 if not found.
+ */
+#define BMH_CHARSET_SIZE 256 /* ISO-Latin-1 */
+#define BMH_PATLEN_MAX 255 /* skip table element is uint8 */
+
+#define BMH_BAD_PATTERN (-2) /* return value if pat is not ISO-Latin-1 */
+
+extern jsint
+js_BoyerMooreHorspool(const jschar *text, jsint textlen,
+ const jschar *pat, jsint patlen,
+ jsint start);
+
+extern size_t
+js_strlen(const jschar *s);
+
+extern jschar *
+js_strchr(const jschar *s, jschar c);
+
+extern jschar *
+js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
+
+#define js_strncpy(t, s, n) memcpy((t), (s), (n) * sizeof(jschar))
+
+/*
+ * Return s advanced past any Unicode white space characters.
+ */
+extern const jschar *
+js_SkipWhiteSpace(const jschar *s);
+
+/*
+ * Inflate bytes to JS chars and vice versa. Report out of memory via cx
+ * and return null on error, otherwise return the jschar or byte vector that
+ * was JS_malloc'ed.
+ */
+extern jschar *
+js_InflateString(JSContext *cx, const char *bytes, size_t length);
+
+extern char *
+js_DeflateString(JSContext *cx, const jschar *chars, size_t length);
+
+/*
+ * Inflate bytes to JS chars into a buffer.
+ * 'chars' must be large enough for 'length'+1 jschars.
+ */
+extern void
+js_InflateStringToBuffer(jschar *chars, const char *bytes, size_t length);
+
+/*
+ * Associate bytes with str in the deflated string cache, returning true on
+ * successful association, false on out of memory.
+ */
+extern JSBool
+js_SetStringBytes(JSString *str, char *bytes, size_t length);
+
+/*
+ * Find or create a deflated string cache entry for str that contains its
+ * characters chopped from Unicode code points into bytes.
+ */
+extern char *
+js_GetStringBytes(JSString *str);
+
+JSBool
+js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval);
+
+JS_END_EXTERN_C
+
+#endif /* jsstr_h___ */
diff --git a/src/dom/js/jstypes.h b/src/dom/js/jstypes.h
new file mode 100644
index 000000000..1709c6461
--- /dev/null
+++ b/src/dom/js/jstypes.h
@@ -0,0 +1,388 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * IBM Corp.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** File: jstypes.h
+** Description: Definitions of NSPR's basic types
+**
+** Prototypes and macros used to make up for deficiencies in ANSI environments
+** that we have found.
+**
+** Since we do not wrap <stdlib.h> and all the other standard headers, authors
+** of portable code will not know in general that they need these definitions.
+** Instead of requiring these authors to find the dependent uses in their code
+** and take the following steps only in those C files, we take steps once here
+** for all C files.
+**/
+
+#ifndef jstypes_h___
+#define jstypes_h___
+
+#include <stddef.h>
+
+/***********************************************************************
+** MACROS: JS_EXTERN_API
+** JS_EXPORT_API
+** DESCRIPTION:
+** These are only for externally visible routines and globals. For
+** internal routines, just use "extern" for type checking and that
+** will not export internal cross-file or forward-declared symbols.
+** Define a macro for declaring procedures return types. We use this to
+** deal with windoze specific type hackery for DLL definitions. Use
+** JS_EXTERN_API when the prototype for the method is declared. Use
+** JS_EXPORT_API for the implementation of the method.
+**
+** Example:
+** in dowhim.h
+** JS_EXTERN_API( void ) DoWhatIMean( void );
+** in dowhim.c
+** JS_EXPORT_API( void ) DoWhatIMean( void ) { return; }
+**
+**
+***********************************************************************/
+#ifdef WIN32
+/* These also work for __MWERKS__ */
+#define JS_EXTERN_API(__type) extern __declspec(dllexport) __type
+#define JS_EXPORT_API(__type) __declspec(dllexport) __type
+#define JS_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define JS_EXPORT_DATA(__type) __declspec(dllexport) __type
+
+#define JS_DLL_CALLBACK
+#define JS_STATIC_DLL_CALLBACK(__x) static __x
+
+#elif defined(WIN16)
+
+#ifdef _WINDLL
+#define JS_EXTERN_API(__type) extern __type _cdecl _export _loadds
+#define JS_EXPORT_API(__type) __type _cdecl _export _loadds
+#define JS_EXTERN_DATA(__type) extern __type _export
+#define JS_EXPORT_DATA(__type) __type _export
+
+#define JS_DLL_CALLBACK __cdecl __loadds
+#define JS_STATIC_DLL_CALLBACK(__x) static __x CALLBACK
+
+#else /* this must be .EXE */
+#define JS_EXTERN_API(__type) extern __type _cdecl _export
+#define JS_EXPORT_API(__type) __type _cdecl _export
+#define JS_EXTERN_DATA(__type) extern __type _export
+#define JS_EXPORT_DATA(__type) __type _export
+
+#define JS_DLL_CALLBACK __cdecl __loadds
+#define JS_STATIC_DLL_CALLBACK(__x) __x JS_DLL_CALLBACK
+#endif /* _WINDLL */
+
+#elif defined(XP_MAC)
+#define JS_EXTERN_API(__type) extern __declspec(export) __type
+#define JS_EXPORT_API(__type) __declspec(export) __type
+#define JS_EXTERN_DATA(__type) extern __declspec(export) __type
+#define JS_EXPORT_DATA(__type) __declspec(export) __type
+
+#define JS_DLL_CALLBACK
+#define JS_STATIC_DLL_CALLBACK(__x) static __x
+
+#else /* Unix */
+
+#define JS_EXTERN_API(__type) extern __type
+#define JS_EXPORT_API(__type) __type
+#define JS_EXTERN_DATA(__type) extern __type
+#define JS_EXPORT_DATA(__type) __type
+
+#define JS_DLL_CALLBACK
+#define JS_STATIC_DLL_CALLBACK(__x) static __x
+
+#endif
+
+#ifdef _WIN32
+# if defined(__MWERKS__) || defined(__GNUC__)
+# define JS_IMPORT_API(__x) __x
+# else
+# define JS_IMPORT_API(__x) __declspec(dllimport) __x
+# endif
+#else
+# define JS_IMPORT_API(__x) JS_EXPORT_API (__x)
+#endif
+
+#if defined(_WIN32) && !defined(__MWERKS__) &&!defined(__GNUC__)
+# define JS_IMPORT_DATA(__x) __declspec(dllimport) __x
+#else
+# define JS_IMPORT_DATA(__x) __x
+#endif
+
+/*
+ * The linkage of JS API functions differs depending on whether the file is
+ * used within the JS library or not. Any source file within the JS
+ * interpreter should define EXPORT_JS_API whereas any client of the library
+ * should not.
+ */
+#ifdef EXPORT_JS_API
+#define JS_PUBLIC_API(t) JS_EXPORT_API(t)
+#define JS_PUBLIC_DATA(t) JS_EXPORT_DATA(t)
+#else
+#define JS_PUBLIC_API(t) JS_IMPORT_API(t)
+#define JS_PUBLIC_DATA(t) JS_IMPORT_DATA(t)
+#endif
+
+#define JS_FRIEND_API(t) JS_PUBLIC_API(t)
+#define JS_FRIEND_DATA(t) JS_PUBLIC_DATA(t)
+
+#ifdef _WIN32
+# define JS_INLINE __inline
+#elif defined(__GNUC__)
+# define JS_INLINE
+#else
+# define JS_INLINE
+#endif
+
+/***********************************************************************
+** MACROS: JS_BEGIN_MACRO
+** JS_END_MACRO
+** DESCRIPTION:
+** Macro body brackets so that macros with compound statement definitions
+** behave syntactically more like functions when called.
+***********************************************************************/
+#define JS_BEGIN_MACRO do {
+#define JS_END_MACRO } while (0)
+
+/***********************************************************************
+** MACROS: JS_BEGIN_EXTERN_C
+** JS_END_EXTERN_C
+** DESCRIPTION:
+** Macro shorthands for conditional C++ extern block delimiters.
+***********************************************************************/
+#ifdef __cplusplus
+#define JS_BEGIN_EXTERN_C extern "C" {
+#define JS_END_EXTERN_C }
+#else
+#define JS_BEGIN_EXTERN_C
+#define JS_END_EXTERN_C
+#endif
+
+/***********************************************************************
+** MACROS: JS_BIT
+** JS_BITMASK
+** DESCRIPTION:
+** Bit masking macros. XXX n must be <= 31 to be portable
+***********************************************************************/
+#define JS_BIT(n) ((JSUint32)1 << (n))
+#define JS_BITMASK(n) (JS_BIT(n) - 1)
+
+/***********************************************************************
+** MACROS: JS_HOWMANY
+** JS_ROUNDUP
+** JS_MIN
+** JS_MAX
+** DESCRIPTION:
+** Commonly used macros for operations on compatible types.
+***********************************************************************/
+#define JS_HOWMANY(x,y) (((x)+(y)-1)/(y))
+#define JS_ROUNDUP(x,y) (JS_HOWMANY(x,y)*(y))
+#define JS_MIN(x,y) ((x)<(y)?(x):(y))
+#define JS_MAX(x,y) ((x)>(y)?(x):(y))
+
+#if (defined(XP_MAC) || defined(XP_WIN)) && !defined(CROSS_COMPILE)
+# include "jscpucfg.h" /* Use standard Mac or Windows configuration */
+#elif defined(XP_UNIX) || defined(XP_BEOS) || defined(XP_OS2) || defined(CROSS_COMPILE)
+# include "jsautocfg.h" /* Use auto-detected configuration */
+# include "jsosdep.h" /* ...and platform-specific flags */
+#else
+# error "Must define one of XP_BEOS, XP_MAC, XP_OS2, XP_WIN or XP_UNIX"
+#endif
+
+JS_BEGIN_EXTERN_C
+
+/************************************************************************
+** TYPES: JSUint8
+** JSInt8
+** DESCRIPTION:
+** The int8 types are known to be 8 bits each. There is no type that
+** is equivalent to a plain "char".
+************************************************************************/
+#if JS_BYTES_PER_BYTE == 1
+typedef unsigned char JSUint8;
+typedef signed char JSInt8;
+#else
+#error No suitable type for JSInt8/JSUint8
+#endif
+
+/************************************************************************
+** TYPES: JSUint16
+** JSInt16
+** DESCRIPTION:
+** The int16 types are known to be 16 bits each.
+************************************************************************/
+#if JS_BYTES_PER_SHORT == 2
+typedef unsigned short JSUint16;
+typedef short JSInt16;
+#else
+#error No suitable type for JSInt16/JSUint16
+#endif
+
+/************************************************************************
+** TYPES: JSUint32
+** JSInt32
+** DESCRIPTION:
+** The int32 types are known to be 32 bits each.
+************************************************************************/
+#if JS_BYTES_PER_INT == 4
+typedef unsigned int JSUint32;
+typedef int JSInt32;
+#define JS_INT32(x) x
+#define JS_UINT32(x) x ## U
+#elif JS_BYTES_PER_LONG == 4
+typedef unsigned long JSUint32;
+typedef long JSInt32;
+#define JS_INT32(x) x ## L
+#define JS_UINT32(x) x ## UL
+#else
+#error No suitable type for JSInt32/JSUint32
+#endif
+
+/************************************************************************
+** TYPES: JSUint64
+** JSInt64
+** DESCRIPTION:
+** The int64 types are known to be 64 bits each. Care must be used when
+** declaring variables of type JSUint64 or JSInt64. Different hardware
+** architectures and even different compilers have varying support for
+** 64 bit values. The only guaranteed portability requires the use of
+** the JSLL_ macros (see jslong.h).
+************************************************************************/
+#ifdef JS_HAVE_LONG_LONG
+#if JS_BYTES_PER_LONG == 8
+typedef long JSInt64;
+typedef unsigned long JSUint64;
+#elif defined(WIN16)
+typedef __int64 JSInt64;
+typedef unsigned __int64 JSUint64;
+#elif defined(WIN32) && !defined(__GNUC__)
+typedef __int64 JSInt64;
+typedef unsigned __int64 JSUint64;
+#else
+typedef long long JSInt64;
+typedef unsigned long long JSUint64;
+#endif /* JS_BYTES_PER_LONG == 8 */
+#else /* !JS_HAVE_LONG_LONG */
+typedef struct {
+#ifdef IS_LITTLE_ENDIAN
+ JSUint32 lo, hi;
+#else
+ JSUint32 hi, lo;
+#endif
+} JSInt64;
+typedef JSInt64 JSUint64;
+#endif /* !JS_HAVE_LONG_LONG */
+
+/************************************************************************
+** TYPES: JSUintn
+** JSIntn
+** DESCRIPTION:
+** The JSIntn types are most appropriate for automatic variables. They are
+** guaranteed to be at least 16 bits, though various architectures may
+** define them to be wider (e.g., 32 or even 64 bits). These types are
+** never valid for fields of a structure.
+************************************************************************/
+#if JS_BYTES_PER_INT >= 2
+typedef int JSIntn;
+typedef unsigned int JSUintn;
+#else
+#error 'sizeof(int)' not sufficient for platform use
+#endif
+
+/************************************************************************
+** TYPES: JSFloat64
+** DESCRIPTION:
+** NSPR's floating point type is always 64 bits.
+************************************************************************/
+typedef double JSFloat64;
+
+/************************************************************************
+** TYPES: JSSize
+** DESCRIPTION:
+** A type for representing the size of objects.
+************************************************************************/
+typedef size_t JSSize;
+
+/************************************************************************
+** TYPES: JSPtrDiff
+** DESCRIPTION:
+** A type for pointer difference. Variables of this type are suitable
+** for storing a pointer or pointer sutraction.
+************************************************************************/
+typedef ptrdiff_t JSPtrdiff;
+
+/************************************************************************
+** TYPES: JSUptrdiff
+** DESCRIPTION:
+** A type for pointer difference. Variables of this type are suitable
+** for storing a pointer or pointer sutraction.
+************************************************************************/
+typedef unsigned long JSUptrdiff;
+
+/************************************************************************
+** TYPES: JSBool
+** DESCRIPTION:
+** Use JSBool for variables and parameter types. Use JS_FALSE and JS_TRUE
+** for clarity of target type in assignments and actual arguments. Use
+** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans
+** just as you would C int-valued conditions.
+************************************************************************/
+typedef JSIntn JSBool;
+#define JS_TRUE (JSIntn)1
+#define JS_FALSE (JSIntn)0
+
+/************************************************************************
+** TYPES: JSPackedBool
+** DESCRIPTION:
+** Use JSPackedBool within structs where bitfields are not desireable
+** but minimum and consistant overhead matters.
+************************************************************************/
+typedef JSUint8 JSPackedBool;
+
+/*
+** A JSWord is an integer that is the same size as a void*
+*/
+typedef long JSWord;
+typedef unsigned long JSUword;
+
+#include "jsotypes.h"
+
+JS_END_EXTERN_C
+
+#endif /* jstypes_h___ */
+
diff --git a/src/dom/js/jsutil.c b/src/dom/js/jsutil.c
new file mode 100644
index 000000000..f64718ad4
--- /dev/null
+++ b/src/dom/js/jsutil.c
@@ -0,0 +1,157 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * IBM Corp.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * PR assertion checker.
+ */
+#include "jsstddef.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "jstypes.h"
+#include "jsutil.h"
+
+#ifdef WIN32
+# include <windows.h>
+#endif
+
+#ifdef XP_MAC
+# include <Types.h>
+# include <stdarg.h>
+# include "jsprf.h"
+#endif
+
+#ifdef XP_MAC
+/*
+ * PStrFromCStr converts the source C string to a destination
+ * pascal string as it copies. The dest string will
+ * be truncated to fit into an Str255 if necessary.
+ * If the C String pointer is NULL, the pascal string's length is
+ * set to zero.
+ */
+static void PStrFromCStr(const char* src, Str255 dst)
+{
+ short length = 0;
+
+ /* handle case of overlapping strings */
+ if ( (void*)src == (void*)dst )
+ {
+ unsigned char* curdst = &dst[1];
+ unsigned char thisChar;
+
+ thisChar = *(const unsigned char*)src++;
+ while ( thisChar != '\0' )
+ {
+ unsigned char nextChar;
+
+ /*
+ * Use nextChar so we don't overwrite what we
+ * are about to read
+ */
+ nextChar = *(const unsigned char*)src++;
+ *curdst++ = thisChar;
+ thisChar = nextChar;
+
+ if ( ++length >= 255 )
+ break;
+ }
+ }
+ else if ( src != NULL )
+ {
+ unsigned char* curdst = &dst[1];
+ /* count down so test it loop is faster */
+ short overflow = 255;
+ register char temp;
+
+ /*
+ * Can't do the K&R C thing of while (*s++ = *t++)
+ * because it will copy trailing zero which might
+ * overrun pascal buffer. Instead we use a temp variable.
+ */
+ while ( (temp = *src++) != 0 )
+ {
+ *(char*)curdst++ = temp;
+
+ if ( --overflow <= 0 )
+ break;
+ }
+ length = 255 - overflow;
+ }
+ dst[0] = length;
+}
+
+static void jsdebugstr(const char *debuggerMsg)
+{
+ Str255 pStr;
+
+ PStrFromCStr(debuggerMsg, pStr);
+ DebugStr(pStr);
+}
+
+static void dprintf(const char *format, ...)
+{
+ va_list ap;
+ char *buffer;
+
+ va_start(ap, format);
+ buffer = (char *)JS_vsmprintf(format, ap);
+ va_end(ap);
+
+ jsdebugstr(buffer);
+ JS_DELETE(buffer);
+}
+#endif /* XP_MAC */
+
+JS_PUBLIC_API(void) JS_Assert(const char *s, const char *file, JSIntn ln)
+{
+#ifdef XP_MAC
+ dprintf("Assertion failure: %s, at %s:%d\n", s, file, ln);
+#else
+ fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
+#endif
+#if defined(WIN32)
+ DebugBreak();
+#endif
+#if defined(XP_OS2)
+ asm("int $3");
+#endif
+#ifndef XP_MAC
+ abort();
+#endif
+}
diff --git a/src/dom/js/jsutil.h b/src/dom/js/jsutil.h
new file mode 100644
index 000000000..d4edb919c
--- /dev/null
+++ b/src/dom/js/jsutil.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * PR assertion checker.
+ */
+
+#ifndef jsutil_h___
+#define jsutil_h___
+
+JS_BEGIN_EXTERN_C
+
+/***********************************************************************
+** FUNCTION: JS_MALLOC()
+** DESCRIPTION:
+** JS_NEW() allocates an untyped item of size _size from the heap.
+** INPUTS: _size: size in bytes of item to be allocated
+** OUTPUTS: untyped pointer to the node allocated
+** RETURN: pointer to node or error returned from malloc().
+***********************************************************************/
+#define JS_MALLOC(_bytes) (malloc((_bytes)))
+
+/***********************************************************************
+** FUNCTION: JS_DELETE()
+** DESCRIPTION:
+** JS_DELETE() unallocates an object previosly allocated via JS_NEW()
+** or JS_NEWZAP() to the heap.
+** INPUTS: pointer to previously allocated object
+** OUTPUTS: the referenced object is returned to the heap
+** RETURN: void
+***********************************************************************/
+#define JS_DELETE(_ptr) { free(_ptr); (_ptr) = NULL; }
+
+/***********************************************************************
+** FUNCTION: JS_NEW()
+** DESCRIPTION:
+** JS_NEW() allocates an item of type _struct from the heap.
+** INPUTS: _struct: a data type
+** OUTPUTS: pointer to _struct
+** RETURN: pointer to _struct or error returns from malloc().
+***********************************************************************/
+#define JS_NEW(_struct) ((_struct *) JS_MALLOC(sizeof(_struct)))
+
+#ifdef DEBUG
+
+extern JS_PUBLIC_API(void)
+JS_Assert(const char *s, const char *file, JSIntn ln);
+#define JS_ASSERT(_expr) \
+ ((_expr)?((void)0):JS_Assert(# _expr,__FILE__,__LINE__))
+
+#define JS_NOT_REACHED(_reasonStr) \
+ JS_Assert(_reasonStr,__FILE__,__LINE__)
+
+#else
+
+#define JS_ASSERT(expr) ((void) 0)
+#define JS_NOT_REACHED(reasonStr)
+
+#endif /* defined(DEBUG) */
+
+/*
+** Abort the process in a non-graceful manner. This will cause a core file,
+** call to the debugger or other moral equivalent as well as causing the
+** entire process to stop.
+*/
+extern JS_PUBLIC_API(void) JS_Abort(void);
+
+JS_END_EXTERN_C
+
+#endif /* jsutil_h___ */
diff --git a/src/dom/js/jsxdrapi.c b/src/dom/js/jsxdrapi.c
new file mode 100644
index 000000000..1b092924d
--- /dev/null
+++ b/src/dom/js/jsxdrapi.c
@@ -0,0 +1,690 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#include "jsstddef.h"
+#include "jsconfig.h"
+
+#if JS_HAS_XDR
+
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jsdhash.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsobj.h" /* js_XDRObject */
+#include "jsscript.h" /* js_XDRScript */
+#include "jsstr.h"
+#include "jsxdrapi.h"
+
+#ifdef DEBUG
+#define DBG(x) x
+#else
+#define DBG(x) ((void)0)
+#endif
+
+typedef struct JSXDRMemState {
+ JSXDRState state;
+ char *base;
+ uint32 count;
+ uint32 limit;
+} JSXDRMemState;
+
+#define MEM_BLOCK 8192
+#define MEM_PRIV(xdr) ((JSXDRMemState *)(xdr))
+
+#define MEM_BASE(xdr) (MEM_PRIV(xdr)->base)
+#define MEM_COUNT(xdr) (MEM_PRIV(xdr)->count)
+#define MEM_LIMIT(xdr) (MEM_PRIV(xdr)->limit)
+
+#define MEM_LEFT(xdr, bytes) \
+ JS_BEGIN_MACRO \
+ if ((xdr)->mode == JSXDR_DECODE && \
+ MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
+ JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \
+ JSMSG_END_OF_DATA); \
+ return 0; \
+ } \
+ JS_END_MACRO
+
+#define MEM_NEED(xdr, bytes) \
+ JS_BEGIN_MACRO \
+ if ((xdr)->mode == JSXDR_ENCODE) { \
+ if (MEM_LIMIT(xdr) && \
+ MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
+ uint32 limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\
+ void *data_ = JS_realloc((xdr)->cx, MEM_BASE(xdr), limit_); \
+ if (!data_) \
+ return 0; \
+ MEM_BASE(xdr) = data_; \
+ MEM_LIMIT(xdr) = limit_; \
+ } \
+ } else { \
+ MEM_LEFT(xdr, bytes); \
+ } \
+ JS_END_MACRO
+
+#define MEM_DATA(xdr) ((void *)(MEM_BASE(xdr) + MEM_COUNT(xdr)))
+#define MEM_INCR(xdr,bytes) (MEM_COUNT(xdr) += (bytes))
+
+static JSBool
+mem_get32(JSXDRState *xdr, uint32 *lp)
+{
+ MEM_LEFT(xdr, 4);
+ *lp = *(uint32 *)MEM_DATA(xdr);
+ MEM_INCR(xdr, 4);
+ return JS_TRUE;
+}
+
+static JSBool
+mem_set32(JSXDRState *xdr, uint32 *lp)
+{
+ MEM_NEED(xdr, 4);
+ *(uint32 *)MEM_DATA(xdr) = *lp;
+ MEM_INCR(xdr, 4);
+ return JS_TRUE;
+}
+
+static JSBool
+mem_getbytes(JSXDRState *xdr, char *bytes, uint32 len)
+{
+ MEM_LEFT(xdr, len);
+ memcpy(bytes, MEM_DATA(xdr), len);
+ MEM_INCR(xdr, len);
+ return JS_TRUE;
+}
+
+static JSBool
+mem_setbytes(JSXDRState *xdr, char *bytes, uint32 len)
+{
+ MEM_NEED(xdr, len);
+ memcpy(MEM_DATA(xdr), bytes, len);
+ MEM_INCR(xdr, len);
+ return JS_TRUE;
+}
+
+static void *
+mem_raw(JSXDRState *xdr, uint32 len)
+{
+ void *data;
+ if (xdr->mode == JSXDR_ENCODE) {
+ MEM_NEED(xdr, len);
+ } else if (xdr->mode == JSXDR_DECODE) {
+ MEM_LEFT(xdr, len);
+ }
+ data = MEM_DATA(xdr);
+ MEM_INCR(xdr, len);
+ return data;
+}
+
+static JSBool
+mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence)
+{
+ switch (whence) {
+ case JSXDR_SEEK_CUR:
+ if ((int32)MEM_COUNT(xdr) + offset < 0) {
+ JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+ JSMSG_SEEK_BEYOND_START);
+ return JS_FALSE;
+ }
+ if (offset > 0)
+ MEM_NEED(xdr, offset);
+ MEM_COUNT(xdr) += offset;
+ return JS_TRUE;
+ case JSXDR_SEEK_SET:
+ if (offset < 0) {
+ JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+ JSMSG_SEEK_BEYOND_START);
+ return JS_FALSE;
+ }
+ if (xdr->mode == JSXDR_ENCODE) {
+ if ((uint32)offset > MEM_COUNT(xdr))
+ MEM_NEED(xdr, offset - MEM_COUNT(xdr));
+ MEM_COUNT(xdr) = offset;
+ } else {
+ if ((uint32)offset > MEM_LIMIT(xdr)) {
+ JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+ JSMSG_SEEK_BEYOND_END);
+ return JS_FALSE;
+ }
+ MEM_COUNT(xdr) = offset;
+ }
+ return JS_TRUE;
+ case JSXDR_SEEK_END:
+ if (offset >= 0 ||
+ xdr->mode == JSXDR_ENCODE ||
+ (int32)MEM_LIMIT(xdr) + offset < 0) {
+ JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+ JSMSG_END_SEEK);
+ return JS_FALSE;
+ }
+ MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset;
+ return JS_TRUE;
+ default: {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%d", whence);
+ JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+ JSMSG_WHITHER_WHENCE, numBuf);
+ return JS_FALSE;
+ }
+ }
+}
+
+static uint32
+mem_tell(JSXDRState *xdr)
+{
+ return MEM_COUNT(xdr);
+}
+
+static void
+mem_finalize(JSXDRState *xdr)
+{
+ JS_free(xdr->cx, MEM_BASE(xdr));
+}
+
+static JSXDROps xdrmem_ops = {
+ mem_get32, mem_set32, mem_getbytes, mem_setbytes,
+ mem_raw, mem_seek, mem_tell, mem_finalize
+};
+
+JS_PUBLIC_API(void)
+JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx)
+{
+ xdr->mode = mode;
+ xdr->cx = cx;
+ xdr->registry = NULL;
+ xdr->numclasses = xdr->maxclasses = 0;
+ xdr->reghash = NULL;
+ xdr->userdata = NULL;
+}
+
+JS_PUBLIC_API(JSXDRState *)
+JS_XDRNewMem(JSContext *cx, JSXDRMode mode)
+{
+ JSXDRState *xdr = (JSXDRState *) JS_malloc(cx, sizeof(JSXDRMemState));
+ if (!xdr)
+ return NULL;
+ JS_XDRInitBase(xdr, mode, cx);
+ if (mode == JSXDR_ENCODE) {
+ if (!(MEM_BASE(xdr) = JS_malloc(cx, MEM_BLOCK))) {
+ JS_free(cx, xdr);
+ return NULL;
+ }
+ } else {
+ /* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */
+ MEM_BASE(xdr) = NULL;
+ }
+ xdr->ops = &xdrmem_ops;
+ MEM_COUNT(xdr) = 0;
+ MEM_LIMIT(xdr) = MEM_BLOCK;
+ return xdr;
+}
+
+JS_PUBLIC_API(void *)
+JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp)
+{
+ if (xdr->ops != &xdrmem_ops)
+ return NULL;
+ *lp = MEM_COUNT(xdr);
+ return MEM_BASE(xdr);
+}
+
+JS_PUBLIC_API(void)
+JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len)
+{
+ if (xdr->ops != &xdrmem_ops)
+ return;
+ MEM_LIMIT(xdr) = len;
+ MEM_BASE(xdr) = data;
+ MEM_COUNT(xdr) = 0;
+}
+
+JS_PUBLIC_API(uint32)
+JS_XDRMemDataLeft(JSXDRState *xdr)
+{
+ if (xdr->ops != &xdrmem_ops)
+ return 0;
+ return MEM_LIMIT(xdr) - MEM_COUNT(xdr);
+}
+
+JS_PUBLIC_API(void)
+JS_XDRMemResetData(JSXDRState *xdr)
+{
+ if (xdr->ops != &xdrmem_ops)
+ return;
+ MEM_COUNT(xdr) = 0;
+}
+
+JS_PUBLIC_API(void)
+JS_XDRDestroy(JSXDRState *xdr)
+{
+ JSContext *cx = xdr->cx;
+ xdr->ops->finalize(xdr);
+ if (xdr->registry) {
+ JS_free(cx, xdr->registry);
+ if (xdr->reghash)
+ JS_DHashTableDestroy(xdr->reghash);
+ }
+ JS_free(cx, xdr);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRUint8(JSXDRState *xdr, uint8 *b)
+{
+ uint32 l = *b;
+ if (!JS_XDRUint32(xdr, &l))
+ return JS_FALSE;
+ *b = (uint8) l;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRUint16(JSXDRState *xdr, uint16 *s)
+{
+ uint32 l = *s;
+ if (!JS_XDRUint32(xdr, &l))
+ return JS_FALSE;
+ *s = (uint16) l;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRUint32(JSXDRState *xdr, uint32 *lp)
+{
+ JSBool ok = JS_TRUE;
+ if (xdr->mode == JSXDR_ENCODE) {
+ uint32 xl = JSXDR_SWAB32(*lp);
+ ok = xdr->ops->set32(xdr, &xl);
+ } else if (xdr->mode == JSXDR_DECODE) {
+ ok = xdr->ops->get32(xdr, lp);
+ *lp = JSXDR_SWAB32(*lp);
+ }
+ return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len)
+{
+ uint32 padlen;
+ static char padbuf[JSXDR_ALIGN-1];
+
+ if (xdr->mode == JSXDR_ENCODE) {
+ if (!xdr->ops->setbytes(xdr, bytes, len))
+ return JS_FALSE;
+ } else {
+ if (!xdr->ops->getbytes(xdr, bytes, len))
+ return JS_FALSE;
+ }
+ len = xdr->ops->tell(xdr);
+ if (len % JSXDR_ALIGN) {
+ padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN);
+ if (xdr->mode == JSXDR_ENCODE) {
+ if (!xdr->ops->setbytes(xdr, padbuf, padlen))
+ return JS_FALSE;
+ } else {
+ if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR))
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+/**
+ * Convert between a C string and the XDR representation:
+ * leading 32-bit count, then counted vector of chars,
+ * then possibly \0 padding to multiple of 4.
+ */
+JS_PUBLIC_API(JSBool)
+JS_XDRCString(JSXDRState *xdr, char **sp)
+{
+ uint32 len;
+
+ if (xdr->mode == JSXDR_ENCODE)
+ len = strlen(*sp);
+ JS_XDRUint32(xdr, &len);
+ if (xdr->mode == JSXDR_DECODE) {
+ if (!(*sp = (char *) JS_malloc(xdr->cx, len + 1)))
+ return JS_FALSE;
+ }
+ if (!JS_XDRBytes(xdr, *sp, len)) {
+ if (xdr->mode == JSXDR_DECODE)
+ JS_free(xdr->cx, *sp);
+ return JS_FALSE;
+ }
+ if (xdr->mode == JSXDR_DECODE) {
+ (*sp)[len] = '\0';
+ } else if (xdr->mode == JSXDR_FREE) {
+ JS_free(xdr->cx, *sp);
+ *sp = NULL;
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRCStringOrNull(JSXDRState *xdr, char **sp)
+{
+ uint32 null = (*sp == NULL);
+ if (!JS_XDRUint32(xdr, &null))
+ return JS_FALSE;
+ if (null) {
+ *sp = NULL;
+ return JS_TRUE;
+ }
+ return JS_XDRCString(xdr, sp);
+}
+
+/*
+ * Convert between a JS (Unicode) string and the XDR representation.
+ */
+JS_PUBLIC_API(JSBool)
+JS_XDRString(JSXDRState *xdr, JSString **strp)
+{
+ uint32 i, len, padlen, nbytes;
+ jschar *chars = NULL, *raw;
+
+ if (xdr->mode == JSXDR_ENCODE)
+ len = JSSTRING_LENGTH(*strp);
+ if (!JS_XDRUint32(xdr, &len))
+ return JS_FALSE;
+ nbytes = len * sizeof(jschar);
+
+ if (xdr->mode == JSXDR_DECODE) {
+ if (!(chars = (jschar *) JS_malloc(xdr->cx, nbytes + sizeof(jschar))))
+ return JS_FALSE;
+ } else {
+ chars = JSSTRING_CHARS(*strp);
+ }
+
+ padlen = nbytes % JSXDR_ALIGN;
+ if (padlen) {
+ padlen = JSXDR_ALIGN - padlen;
+ nbytes += padlen;
+ }
+ if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes)))
+ goto bad;
+ if (xdr->mode == JSXDR_ENCODE) {
+ for (i = 0; i < len; i++)
+ raw[i] = JSXDR_SWAB16(chars[i]);
+ if (padlen)
+ memset((char *)raw + nbytes - padlen, 0, padlen);
+ } else if (xdr->mode == JSXDR_DECODE) {
+ for (i = 0; i < len; i++)
+ chars[i] = JSXDR_SWAB16(raw[i]);
+ chars[len] = 0;
+
+ if (!(*strp = JS_NewUCString(xdr->cx, chars, len)))
+ goto bad;
+ }
+ return JS_TRUE;
+
+bad:
+ if (xdr->mode == JSXDR_DECODE)
+ JS_free(xdr->cx, chars);
+ return JS_FALSE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp)
+{
+ uint32 null = (*strp == NULL);
+ if (!JS_XDRUint32(xdr, &null))
+ return JS_FALSE;
+ if (null) {
+ *strp = NULL;
+ return JS_TRUE;
+ }
+ return JS_XDRString(xdr, strp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRDouble(JSXDRState *xdr, jsdouble **dp)
+{
+ jsdouble d;
+ if (xdr->mode == JSXDR_ENCODE)
+ d = **dp;
+#if IS_BIG_ENDIAN
+ if (!JS_XDRUint32(xdr, (uint32 *)&d + 1) ||
+ !JS_XDRUint32(xdr, (uint32 *)&d))
+#else
+ if (!JS_XDRUint32(xdr, (uint32 *)&d) ||
+ !JS_XDRUint32(xdr, (uint32 *)&d + 1))
+#endif
+ return JS_FALSE;
+ if (xdr->mode == JSXDR_DECODE) {
+ *dp = JS_NewDouble(xdr->cx, d);
+ if (!*dp)
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+/* These are magic pseudo-tags: see jsapi.h, near the top, for real tags. */
+#define JSVAL_XDRNULL 0x8
+#define JSVAL_XDRVOID 0xA
+
+JS_PUBLIC_API(JSBool)
+JS_XDRValue(JSXDRState *xdr, jsval *vp)
+{
+ uint32 type;
+
+ if (xdr->mode == JSXDR_ENCODE) {
+ if (JSVAL_IS_NULL(*vp))
+ type = JSVAL_XDRNULL;
+ else if (JSVAL_IS_VOID(*vp))
+ type = JSVAL_XDRVOID;
+ else
+ type = JSVAL_TAG(*vp);
+ }
+ if (!JS_XDRUint32(xdr, &type))
+ return JS_FALSE;
+
+ switch (type) {
+ case JSVAL_XDRNULL:
+ *vp = JSVAL_NULL;
+ break;
+ case JSVAL_XDRVOID:
+ *vp = JSVAL_VOID;
+ break;
+ case JSVAL_STRING: {
+ JSString *str;
+ if (xdr->mode == JSXDR_ENCODE)
+ str = JSVAL_TO_STRING(*vp);
+ if (!JS_XDRString(xdr, &str))
+ return JS_FALSE;
+ if (xdr->mode == JSXDR_DECODE)
+ *vp = STRING_TO_JSVAL(str);
+ break;
+ }
+ case JSVAL_DOUBLE: {
+ jsdouble *dp;
+ if (xdr->mode == JSXDR_ENCODE)
+ dp = JSVAL_TO_DOUBLE(*vp);
+ if (!JS_XDRDouble(xdr, &dp))
+ return JS_FALSE;
+ if (xdr->mode == JSXDR_DECODE)
+ *vp = DOUBLE_TO_JSVAL(dp);
+ break;
+ }
+ case JSVAL_OBJECT: {
+ JSObject *obj;
+ if (xdr->mode == JSXDR_ENCODE)
+ obj = JSVAL_TO_OBJECT(*vp);
+ if (!js_XDRObject(xdr, &obj))
+ return JS_FALSE;
+ if (xdr->mode == JSXDR_DECODE)
+ *vp = OBJECT_TO_JSVAL(obj);
+ break;
+ }
+ case JSVAL_BOOLEAN: {
+ uint32 b;
+ if (xdr->mode == JSXDR_ENCODE)
+ b = (uint32) JSVAL_TO_BOOLEAN(*vp);
+ if (!JS_XDRUint32(xdr, &b))
+ return JS_FALSE;
+ if (xdr->mode == JSXDR_DECODE)
+ *vp = BOOLEAN_TO_JSVAL((JSBool) b);
+ break;
+ }
+ default: {
+ uint32 i;
+
+ JS_ASSERT(type & JSVAL_INT);
+ if (xdr->mode == JSXDR_ENCODE)
+ i = (uint32) JSVAL_TO_INT(*vp);
+ if (!JS_XDRUint32(xdr, &i))
+ return JS_FALSE;
+ if (xdr->mode == JSXDR_DECODE)
+ *vp = INT_TO_JSVAL((int32) i);
+ break;
+ }
+ }
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
+{
+ if (!js_XDRScript(xdr, scriptp, NULL))
+ return JS_FALSE;
+ if (xdr->mode == JSXDR_DECODE)
+ js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
+ return JS_TRUE;
+}
+
+#define CLASS_REGISTRY_MIN 8
+#define CLASS_INDEX_TO_ID(i) ((i)+1)
+#define CLASS_ID_TO_INDEX(id) ((id)-1)
+
+typedef struct JSRegHashEntry {
+ JSDHashEntryHdr hdr;
+ const char *name;
+ uint32 index;
+} JSRegHashEntry;
+
+JS_PUBLIC_API(JSBool)
+JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp)
+{
+ uintN numclasses, maxclasses;
+ JSClass **registry;
+
+ numclasses = xdr->numclasses;
+ maxclasses = xdr->maxclasses;
+ if (numclasses == maxclasses) {
+ maxclasses = (maxclasses == 0) ? CLASS_REGISTRY_MIN : maxclasses << 1;
+ registry = (JSClass **)
+ JS_realloc(xdr->cx, xdr->registry, maxclasses * sizeof(JSClass *));
+ if (!registry)
+ return JS_FALSE;
+ xdr->registry = registry;
+ xdr->maxclasses = maxclasses;
+ } else {
+ JS_ASSERT(numclasses && numclasses < maxclasses);
+ registry = xdr->registry;
+ }
+
+ registry[numclasses] = clasp;
+ if (xdr->reghash) {
+ JSRegHashEntry *entry = (JSRegHashEntry *)
+ JS_DHashTableOperate(xdr->reghash, clasp->name, JS_DHASH_ADD);
+ if (!entry) {
+ JS_ReportOutOfMemory(xdr->cx);
+ return JS_FALSE;
+ }
+ entry->name = clasp->name;
+ entry->index = numclasses;
+ }
+ *idp = CLASS_INDEX_TO_ID(numclasses);
+ xdr->numclasses = ++numclasses;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(uint32)
+JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name)
+{
+ uintN i, numclasses;
+
+ numclasses = xdr->numclasses;
+ if (numclasses >= 10) {
+ JSRegHashEntry *entry;
+
+ /* Bootstrap reghash from registry on first overpopulated Find. */
+ if (!xdr->reghash) {
+ xdr->reghash = JS_NewDHashTable(JS_DHashGetStubOps(), NULL,
+ sizeof(JSRegHashEntry),
+ numclasses);
+ if (xdr->reghash) {
+ for (i = 0; i < numclasses; i++) {
+ JSClass *clasp = xdr->registry[i];
+ entry = (JSRegHashEntry *)
+ JS_DHashTableOperate(xdr->reghash, clasp->name,
+ JS_DHASH_ADD);
+ entry->name = clasp->name;
+ entry->index = i;
+ }
+ }
+ }
+
+ /* If we managed to create reghash, use it for O(1) Find. */
+ if (xdr->reghash) {
+ entry = (JSRegHashEntry *)
+ JS_DHashTableOperate(xdr->reghash, name, JS_DHASH_LOOKUP);
+ if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr))
+ return CLASS_INDEX_TO_ID(entry->index);
+ }
+ }
+
+ /* Only a few classes, or we couldn't malloc reghash: use linear search. */
+ for (i = 0; i < numclasses; i++) {
+ if (!strcmp(name, xdr->registry[i]->name))
+ return CLASS_INDEX_TO_ID(i);
+ }
+ return 0;
+}
+
+JS_PUBLIC_API(JSClass *)
+JS_XDRFindClassById(JSXDRState *xdr, uint32 id)
+{
+ uintN i = CLASS_ID_TO_INDEX(id);
+
+ if (i >= xdr->numclasses)
+ return NULL;
+ return xdr->registry[i];
+}
+
+#endif /* JS_HAS_XDR */
diff --git a/src/dom/js/jsxdrapi.h b/src/dom/js/jsxdrapi.h
new file mode 100644
index 000000000..874a62eeb
--- /dev/null
+++ b/src/dom/js/jsxdrapi.h
@@ -0,0 +1,193 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsxdrapi_h___
+#define jsxdrapi_h___
+
+/*
+ * JS external data representation interface API.
+ *
+ * The XDR system is comprised of three major parts:
+ *
+ * - the state serialization/deserialization APIs, which allow consumers
+ * of the API to serialize JS runtime state (script bytecodes, atom maps,
+ * object graphs, etc.) for later restoration. These portions
+ * are implemented in various appropriate files, such as jsscript.c
+ * for the script portions and jsobj.c for object state.
+ * - the callback APIs through which the runtime requests an opaque
+ * representation of a native object, and through which the runtime
+ * constructs a live native object from an opaque representation. These
+ * portions are the responsibility of the native object implementor.
+ * - utility functions for en/decoding of primitive types, such as
+ * JSStrings. This portion is implemented in jsxdrapi.c.
+ *
+ * Spiritually guided by Sun's XDR, where appropriate.
+ */
+
+#include "jspubtd.h"
+#include "jsprvtd.h"
+
+JS_BEGIN_EXTERN_C
+
+/* We use little-endian byteorder for all encoded data */
+
+#if defined IS_LITTLE_ENDIAN
+#define JSXDR_SWAB32(x) x
+#define JSXDR_SWAB16(x) x
+#elif defined IS_BIG_ENDIAN
+#define JSXDR_SWAB32(x) (((uint32)(x) >> 24) | \
+ (((uint32)(x) >> 8) & 0xff00) | \
+ (((uint32)(x) << 8) & 0xff0000) | \
+ ((uint32)(x) << 24))
+#define JSXDR_SWAB16(x) (((uint16)(x) >> 8) | ((uint16)(x) << 8))
+#else
+#error "unknown byte order"
+#endif
+
+#define JSXDR_ALIGN 4
+
+typedef enum JSXDRMode {
+ JSXDR_ENCODE,
+ JSXDR_DECODE,
+ JSXDR_FREE
+} JSXDRMode;
+
+typedef enum JSXDRWhence {
+ JSXDR_SEEK_SET,
+ JSXDR_SEEK_CUR,
+ JSXDR_SEEK_END
+} JSXDRWhence;
+
+typedef struct JSXDROps {
+ JSBool (*get32)(JSXDRState *, uint32 *);
+ JSBool (*set32)(JSXDRState *, uint32 *);
+ JSBool (*getbytes)(JSXDRState *, char *, uint32);
+ JSBool (*setbytes)(JSXDRState *, char *, uint32);
+ void * (*raw)(JSXDRState *, uint32);
+ JSBool (*seek)(JSXDRState *, int32, JSXDRWhence);
+ uint32 (*tell)(JSXDRState *);
+ void (*finalize)(JSXDRState *);
+} JSXDROps;
+
+struct JSXDRState {
+ JSXDRMode mode;
+ JSXDROps *ops;
+ JSContext *cx;
+ JSClass **registry;
+ uintN numclasses;
+ uintN maxclasses;
+ void *reghash;
+ void *userdata;
+};
+
+extern JS_PUBLIC_API(void)
+JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx);
+
+extern JS_PUBLIC_API(JSXDRState *)
+JS_XDRNewMem(JSContext *cx, JSXDRMode mode);
+
+extern JS_PUBLIC_API(void *)
+JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp);
+
+extern JS_PUBLIC_API(void)
+JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len);
+
+extern JS_PUBLIC_API(uint32)
+JS_XDRMemDataLeft(JSXDRState *xdr);
+
+extern JS_PUBLIC_API(void)
+JS_XDRMemResetData(JSXDRState *xdr);
+
+extern JS_PUBLIC_API(void)
+JS_XDRDestroy(JSXDRState *xdr);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRUint8(JSXDRState *xdr, uint8 *b);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRUint16(JSXDRState *xdr, uint16 *s);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRUint32(JSXDRState *xdr, uint32 *lp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRCString(JSXDRState *xdr, char **sp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRCStringOrNull(JSXDRState *xdr, char **sp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRString(JSXDRState *xdr, JSString **strp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRDouble(JSXDRState *xdr, jsdouble **dp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRValue(JSXDRState *xdr, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRScript(JSXDRState *xdr, JSScript **scriptp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *lp);
+
+extern JS_PUBLIC_API(uint32)
+JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name);
+
+extern JS_PUBLIC_API(JSClass *)
+JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
+
+/*
+ * Magic numbers.
+ */
+#define JSXDR_MAGIC_SCRIPT_1 0xdead0001
+#define JSXDR_MAGIC_SCRIPT_2 0xdead0002
+#define JSXDR_MAGIC_SCRIPT_3 0xdead0003
+#define JSXDR_MAGIC_SCRIPT_4 0xdead0004
+#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_4
+
+JS_END_EXTERN_C
+
+#endif /* ! jsxdrapi_h___ */
diff --git a/src/dom/js/prmjtime.c b/src/dom/js/prmjtime.c
new file mode 100644
index 000000000..0a53f76bf
--- /dev/null
+++ b/src/dom/js/prmjtime.c
@@ -0,0 +1,646 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * PR time code.
+ */
+#include "jsstddef.h"
+#ifdef SOLARIS
+#define _REENTRANT 1
+#endif
+#include <string.h>
+#include <time.h>
+#include "jstypes.h"
+#include "jsutil.h"
+
+#include "jsprf.h"
+#include "prmjtime.h"
+
+#define PRMJ_DO_MILLISECONDS 1
+
+#ifdef XP_OS2
+#include <sys/timeb.h>
+#endif
+#ifdef XP_WIN
+#include <windef.h>
+#include <winbase.h>
+#endif
+
+#ifdef XP_MAC
+#include <OSUtils.h>
+#include <TextUtils.h>
+#include <Resources.h>
+#include <Timer.h>
+#include <UTCUtils.h>
+#include <Power.h>
+#include <CodeFragments.h>
+#if !TARGET_CARBON
+#include <Traps.h>
+#endif
+#endif
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+extern int gettimeofday(struct timeval *tv);
+#endif
+
+#include <sys/time.h>
+
+#endif /* XP_UNIX */
+
+#ifdef XP_MAC
+static uint64 dstLocalBaseMicroseconds;
+static unsigned long gJanuaryFirst1970Seconds;
+
+static void MacintoshInitializeTime(void)
+{
+ uint64 upTime;
+ unsigned long currentLocalTimeSeconds,
+ startupTimeSeconds;
+ uint64 startupTimeMicroSeconds;
+ uint32 upTimeSeconds;
+ uint64 oneMillion, upTimeSecondsLong, microSecondsToSeconds;
+ DateTimeRec firstSecondOfUnixTime;
+
+ /*
+ * Figure out in local time what time the machine started up. This information can be added to
+ * upTime to figure out the current local time as well as GMT.
+ */
+
+ Microseconds((UnsignedWide*)&upTime);
+
+ GetDateTime(&currentLocalTimeSeconds);
+
+ JSLL_I2L(microSecondsToSeconds, PRMJ_USEC_PER_SEC);
+ JSLL_DIV(upTimeSecondsLong, upTime, microSecondsToSeconds);
+ JSLL_L2I(upTimeSeconds, upTimeSecondsLong);
+
+ startupTimeSeconds = currentLocalTimeSeconds - upTimeSeconds;
+
+ /* Make sure that we normalize the macintosh base seconds to the unix base of January 1, 1970.
+ */
+
+ firstSecondOfUnixTime.year = 1970;
+ firstSecondOfUnixTime.month = 1;
+ firstSecondOfUnixTime.day = 1;
+ firstSecondOfUnixTime.hour = 0;
+ firstSecondOfUnixTime.minute = 0;
+ firstSecondOfUnixTime.second = 0;
+ firstSecondOfUnixTime.dayOfWeek = 0;
+
+ DateToSeconds(&firstSecondOfUnixTime, &gJanuaryFirst1970Seconds);
+
+ startupTimeSeconds -= gJanuaryFirst1970Seconds;
+
+ /* Now convert the startup time into a wide so that we can figure out GMT and DST.
+ */
+
+ JSLL_I2L(startupTimeMicroSeconds, startupTimeSeconds);
+ JSLL_I2L(oneMillion, PRMJ_USEC_PER_SEC);
+ JSLL_MUL(dstLocalBaseMicroseconds, oneMillion, startupTimeMicroSeconds);
+}
+
+static SleepQRec gSleepQEntry = { NULL, sleepQType, NULL, 0 };
+static JSBool gSleepQEntryInstalled = JS_FALSE;
+
+static pascal long MySleepQProc(long message, SleepQRecPtr sleepQ)
+{
+ /* just woke up from sleeping, so must recompute dstLocalBaseMicroseconds. */
+ if (message == kSleepWakeUp)
+ MacintoshInitializeTime();
+ return 0;
+}
+
+/* Because serial port and SLIP conflict with ReadXPram calls,
+ * we cache the call here
+ */
+
+static void MyReadLocation(MachineLocation * loc)
+{
+ static MachineLocation storedLoc; /* InsideMac, OSUtilities, page 4-20 */
+ static JSBool didReadLocation = JS_FALSE;
+ if (!didReadLocation)
+ {
+ MacintoshInitializeTime();
+ ReadLocation(&storedLoc);
+ /* install a sleep queue routine, so that when the machine wakes up, time can be recomputed. */
+ if (&SleepQInstall != (void*)kUnresolvedCFragSymbolAddress
+#if !TARGET_CARBON
+ && NGetTrapAddress(0xA28A, OSTrap) != NGetTrapAddress(_Unimplemented, ToolTrap)
+#endif
+ ) {
+ if ((gSleepQEntry.sleepQProc = NewSleepQUPP(MySleepQProc)) != NULL) {
+ SleepQInstall(&gSleepQEntry);
+ gSleepQEntryInstalled = JS_TRUE;
+ }
+ }
+ didReadLocation = JS_TRUE;
+ }
+ *loc = storedLoc;
+}
+
+
+#ifndef XP_MACOSX
+
+/* CFM library init and terminate routines. We'll use the terminate routine
+ to clean up the sleep Q entry. On Mach-O, the sleep Q entry gets cleaned
+ up for us, so nothing to do there.
+*/
+
+extern pascal OSErr __NSInitialize(const CFragInitBlock* initBlock);
+extern pascal void __NSTerminate();
+
+pascal OSErr __JSInitialize(const CFragInitBlock* initBlock);
+pascal void __JSTerminate(void);
+
+pascal OSErr __JSInitialize(const CFragInitBlock* initBlock)
+{
+ return __NSInitialize(initBlock);
+}
+
+pascal void __JSTerminate()
+{
+ /* clean up the sleepQ entry */
+ if (gSleepQEntryInstalled)
+ SleepQRemove(&gSleepQEntry);
+
+ __NSTerminate();
+}
+#endif /* XP_MACOSX */
+
+#endif /* XP_MAC */
+
+#define IS_LEAP(year) \
+ (year != 0 && ((((year & 0x3) == 0) && \
+ ((year - ((year/100) * 100)) != 0)) || \
+ (year - ((year/400) * 400)) == 0))
+
+#define PRMJ_HOUR_SECONDS 3600L
+#define PRMJ_DAY_SECONDS (24L * PRMJ_HOUR_SECONDS)
+#define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * 365L)
+#define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */
+/* function prototypes */
+static void PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm);
+/*
+ * get the difference in seconds between this time zone and UTC (GMT)
+ */
+JSInt32
+PRMJ_LocalGMTDifference()
+{
+#if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)
+ struct tm ltime;
+
+ /* get the difference between this time zone and GMT */
+ memset((char *)&ltime,0,sizeof(ltime));
+ ltime.tm_mday = 2;
+ ltime.tm_year = 70;
+#ifdef SUNOS4
+ ltime.tm_zone = 0;
+ ltime.tm_gmtoff = 0;
+ return timelocal(&ltime) - (24 * 3600);
+#else
+ return mktime(&ltime) - (24L * 3600L);
+#endif
+#endif
+#if defined(XP_MAC)
+ static JSInt32 zone = -1L;
+ MachineLocation machineLocation;
+ JSInt32 gmtOffsetSeconds;
+
+ /* difference has been set no need to recalculate */
+ if (zone != -1)
+ return zone;
+
+ /* Get the information about the local machine, including
+ * its GMT offset and its daylight savings time info.
+ * Convert each into wides that we can add to
+ * startupTimeMicroSeconds.
+ */
+
+ MyReadLocation(&machineLocation);
+
+ /* Mask off top eight bits of gmtDelta, sign extend lower three. */
+ gmtOffsetSeconds = (machineLocation.u.gmtDelta << 8);
+ gmtOffsetSeconds >>= 8;
+
+ /* Backout OS adjustment for DST, to give consistent GMT offset. */
+ if (machineLocation.u.dlsDelta != 0)
+ gmtOffsetSeconds -= PRMJ_HOUR_SECONDS;
+ return (zone = -gmtOffsetSeconds);
+#endif
+}
+
+/* Constants for GMT offset from 1970 */
+#define G1970GMTMICROHI 0x00dcdcad /* micro secs to 1970 hi */
+#define G1970GMTMICROLOW 0x8b3fa000 /* micro secs to 1970 low */
+
+#define G2037GMTMICROHI 0x00e45fab /* micro secs to 2037 high */
+#define G2037GMTMICROLOW 0x7a238000 /* micro secs to 2037 low */
+
+/* Convert from base time to extended time */
+static JSInt64
+PRMJ_ToExtendedTime(JSInt32 base_time)
+{
+ JSInt64 exttime;
+ JSInt64 g1970GMTMicroSeconds;
+ JSInt64 low;
+ JSInt32 diff;
+ JSInt64 tmp;
+ JSInt64 tmp1;
+
+ diff = PRMJ_LocalGMTDifference();
+ JSLL_UI2L(tmp, PRMJ_USEC_PER_SEC);
+ JSLL_I2L(tmp1,diff);
+ JSLL_MUL(tmp,tmp,tmp1);
+
+ JSLL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI);
+ JSLL_UI2L(low,G1970GMTMICROLOW);
+#ifndef JS_HAVE_LONG_LONG
+ JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
+ JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
+#else
+ JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,32);
+#endif
+ JSLL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low);
+
+ JSLL_I2L(exttime,base_time);
+ JSLL_ADD(exttime,exttime,g1970GMTMicroSeconds);
+ JSLL_SUB(exttime,exttime,tmp);
+ return exttime;
+}
+
+JSInt64
+PRMJ_Now(void)
+{
+#ifdef XP_OS2
+ JSInt64 s, us, ms2us, s2us;
+ struct timeb b;
+#endif
+#ifdef XP_WIN
+ JSInt64 s, us,
+ win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000),
+ ten = JSLL_INIT(0, 10);
+ FILETIME time, midnight;
+#endif
+#if defined(XP_UNIX) || defined(XP_BEOS)
+ struct timeval tv;
+ JSInt64 s, us, s2us;
+#endif /* XP_UNIX */
+#ifdef XP_MAC
+ JSUint64 upTime;
+ JSInt64 localTime;
+ JSInt64 gmtOffset;
+ JSInt64 dstOffset;
+ JSInt32 gmtDiff;
+ JSInt64 s2us;
+#endif /* XP_MAC */
+
+#ifdef XP_OS2
+ ftime(&b);
+ JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC);
+ JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
+ JSLL_UI2L(s, b.time);
+ JSLL_UI2L(us, b.millitm);
+ JSLL_MUL(us, us, ms2us);
+ JSLL_MUL(s, s, s2us);
+ JSLL_ADD(s, s, us);
+ return s;
+#endif
+#ifdef XP_WIN
+ /* The windows epoch is around 1600. The unix epoch is around 1970.
+ win2un is the difference (in windows time units which are 10 times
+ more precise than the JS time unit) */
+ GetSystemTimeAsFileTime(&time);
+ /* Win9x gets confused at midnight
+ http://support.microsoft.com/default.aspx?scid=KB;en-us;q224423
+ So if the low part (precision <8mins) is 0 then we get the time
+ again. */
+ if (!time.dwLowDateTime) {
+ GetSystemTimeAsFileTime(&midnight);
+ time.dwHighDateTime = midnight.dwHighDateTime;
+ }
+ JSLL_UI2L(s, time.dwHighDateTime);
+ JSLL_UI2L(us, time.dwLowDateTime);
+ JSLL_SHL(s, s, 32);
+ JSLL_ADD(s, s, us);
+ JSLL_SUB(s, s, win2un);
+ JSLL_DIV(s, s, ten);
+ return s;
+#endif
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+ gettimeofday(&tv);
+#else
+ gettimeofday(&tv, 0);
+#endif /* _SVID_GETTOD */
+ JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
+ JSLL_UI2L(s, tv.tv_sec);
+ JSLL_UI2L(us, tv.tv_usec);
+ JSLL_MUL(s, s, s2us);
+ JSLL_ADD(s, s, us);
+ return s;
+#endif /* XP_UNIX */
+#ifdef XP_MAC
+ JSLL_UI2L(localTime,0);
+ gmtDiff = PRMJ_LocalGMTDifference();
+ JSLL_I2L(gmtOffset,gmtDiff);
+ JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
+ JSLL_MUL(gmtOffset,gmtOffset,s2us);
+
+ /* don't adjust for DST since it sets ctime and gmtime off on the MAC */
+ Microseconds((UnsignedWide*)&upTime);
+ JSLL_ADD(localTime,localTime,gmtOffset);
+ JSLL_ADD(localTime,localTime, dstLocalBaseMicroseconds);
+ JSLL_ADD(localTime,localTime, upTime);
+
+ dstOffset = PRMJ_DSTOffset(localTime);
+ JSLL_SUB(localTime,localTime,dstOffset);
+
+ return *((JSUint64 *)&localTime);
+#endif /* XP_MAC */
+}
+
+/* Get the DST timezone offset for the time passed in */
+JSInt64
+PRMJ_DSTOffset(JSInt64 local_time)
+{
+ JSInt64 us2s;
+#ifdef XP_MAC
+ /*
+ * Convert the local time passed in to Macintosh epoch seconds. Use UTC utilities to convert
+ * to UTC time, then compare difference with our GMT offset. If they are the same, then
+ * DST must not be in effect for the input date/time.
+ */
+ UInt32 macLocalSeconds = (local_time / PRMJ_USEC_PER_SEC) + gJanuaryFirst1970Seconds, utcSeconds;
+ ConvertLocalTimeToUTC(macLocalSeconds, &utcSeconds);
+ if ((utcSeconds - macLocalSeconds) == PRMJ_LocalGMTDifference())
+ return 0;
+ else {
+ JSInt64 dlsOffset;
+ JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC);
+ JSLL_UI2L(dlsOffset, PRMJ_HOUR_SECONDS);
+ JSLL_MUL(dlsOffset, dlsOffset, us2s);
+ return dlsOffset;
+ }
+#else
+ time_t local;
+ JSInt32 diff;
+ JSInt64 maxtimet;
+ struct tm tm;
+ PRMJTime prtm;
+#ifndef HAVE_LOCALTIME_R
+ struct tm *ptm;
+#endif
+
+
+ JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC);
+ JSLL_DIV(local_time, local_time, us2s);
+
+ /* get the maximum of time_t value */
+ JSLL_UI2L(maxtimet,PRMJ_MAX_UNIX_TIMET);
+
+ if(JSLL_CMP(local_time,>,maxtimet)){
+ JSLL_UI2L(local_time,PRMJ_MAX_UNIX_TIMET);
+ } else if(!JSLL_GE_ZERO(local_time)){
+ /*go ahead a day to make localtime work (does not work with 0) */
+ JSLL_UI2L(local_time,PRMJ_DAY_SECONDS);
+ }
+ JSLL_L2UI(local,local_time);
+ PRMJ_basetime(local_time,&prtm);
+#ifndef HAVE_LOCALTIME_R
+ ptm = localtime(&local);
+ if(!ptm){
+ return JSLL_ZERO;
+ }
+ tm = *ptm;
+#else
+ localtime_r(&local,&tm); /* get dst information */
+#endif
+
+ diff = ((tm.tm_hour - prtm.tm_hour) * PRMJ_HOUR_SECONDS) +
+ ((tm.tm_min - prtm.tm_min) * 60);
+
+ if(diff < 0){
+ diff += PRMJ_DAY_SECONDS;
+ }
+
+ JSLL_UI2L(local_time,diff);
+
+ JSLL_MUL(local_time,local_time,us2s);
+
+ return(local_time);
+#endif
+}
+
+/* Format a time value into a buffer. Same semantics as strftime() */
+size_t
+PRMJ_FormatTime(char *buf, int buflen, char *fmt, PRMJTime *prtm)
+{
+#if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_MAC) || defined(XP_BEOS)
+ struct tm a;
+
+ /* Zero out the tm struct. Linux, SunOS 4 struct tm has extra members int
+ * tm_gmtoff, char *tm_zone; when tm_zone is garbage, strftime gets
+ * confused and dumps core. NSPR20 prtime.c attempts to fill these in by
+ * calling mktime on the partially filled struct, but this doesn't seem to
+ * work as well; the result string has "can't get timezone" for ECMA-valid
+ * years. Might still make sense to use this, but find the range of years
+ * for which valid tz information exists, and map (per ECMA hint) from the
+ * given year into that range.
+
+ * N.B. This hasn't been tested with anything that actually _uses_
+ * tm_gmtoff; zero might be the wrong thing to set it to if you really need
+ * to format a time. This fix is for jsdate.c, which only uses
+ * JS_FormatTime to get a string representing the time zone. */
+ memset(&a, 0, sizeof(struct tm));
+
+ a.tm_sec = prtm->tm_sec;
+ a.tm_min = prtm->tm_min;
+ a.tm_hour = prtm->tm_hour;
+ a.tm_mday = prtm->tm_mday;
+ a.tm_mon = prtm->tm_mon;
+ a.tm_wday = prtm->tm_wday;
+ a.tm_year = prtm->tm_year - 1900;
+ a.tm_yday = prtm->tm_yday;
+ a.tm_isdst = prtm->tm_isdst;
+
+ /* Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff
+ * are null. This doesn't quite work, though - the timezone is off by
+ * tzoff + dst. (And mktime seems to return -1 for the exact dst
+ * changeover time.)
+
+ */
+
+#if defined(SUNOS4)
+ if (mktime(&a) == -1) {
+ /* Seems to fail whenever the requested date is outside of the 32-bit
+ * UNIX epoch. We could proceed at this point (setting a.tm_zone to
+ * "") but then strftime returns a string with a 2-digit field of
+ * garbage for the year. So we return 0 and hope jsdate.c
+ * will fall back on toString.
+ */
+ return 0;
+ }
+#endif
+
+ return strftime(buf, buflen, fmt, &a);
+#endif
+}
+
+/* table for number of days in a month */
+static int mtab[] = {
+ /* jan, feb,mar,apr,may,jun */
+ 31,28,31,30,31,30,
+ /* july,aug,sep,oct,nov,dec */
+ 31,31,30,31,30,31
+};
+
+/*
+ * basic time calculation functionality for localtime and gmtime
+ * setups up prtm argument with correct values based upon input number
+ * of seconds.
+ */
+static void
+PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm)
+{
+ /* convert tsecs back to year,month,day,hour,secs */
+ JSInt32 year = 0;
+ JSInt32 month = 0;
+ JSInt32 yday = 0;
+ JSInt32 mday = 0;
+ JSInt32 wday = 6; /* start on a Sunday */
+ JSInt32 days = 0;
+ JSInt32 seconds = 0;
+ JSInt32 minutes = 0;
+ JSInt32 hours = 0;
+ JSInt32 isleap = 0;
+ JSInt64 result;
+ JSInt64 result1;
+ JSInt64 result2;
+ JSInt64 base;
+
+ JSLL_UI2L(result,0);
+ JSLL_UI2L(result1,0);
+ JSLL_UI2L(result2,0);
+
+ /* get the base time via UTC */
+ base = PRMJ_ToExtendedTime(0);
+ JSLL_UI2L(result, PRMJ_USEC_PER_SEC);
+ JSLL_DIV(base,base,result);
+ JSLL_ADD(tsecs,tsecs,base);
+
+ JSLL_UI2L(result, PRMJ_YEAR_SECONDS);
+ JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
+ JSLL_ADD(result2,result,result1);
+
+ /* get the year */
+ while ((isleap == 0) ? !JSLL_CMP(tsecs,<,result) : !JSLL_CMP(tsecs,<,result2)) {
+ /* subtract a year from tsecs */
+ JSLL_SUB(tsecs,tsecs,result);
+ days += 365;
+ /* is it a leap year ? */
+ if(IS_LEAP(year)){
+ JSLL_SUB(tsecs,tsecs,result1);
+ days++;
+ }
+ year++;
+ isleap = IS_LEAP(year);
+ }
+
+ JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
+
+ JSLL_DIV(result,tsecs,result1);
+ JSLL_L2I(mday,result);
+
+ /* let's find the month */
+ while(((month == 1 && isleap) ?
+ (mday >= mtab[month] + 1) :
+ (mday >= mtab[month]))){
+ yday += mtab[month];
+ days += mtab[month];
+
+ mday -= mtab[month];
+
+ /* it's a Feb, check if this is a leap year */
+ if(month == 1 && isleap != 0){
+ yday++;
+ days++;
+ mday--;
+ }
+ month++;
+ }
+
+ /* now adjust tsecs */
+ JSLL_MUL(result,result,result1);
+ JSLL_SUB(tsecs,tsecs,result);
+
+ mday++; /* day of month always start with 1 */
+ days += mday;
+ wday = (days + wday) % 7;
+
+ yday += mday;
+
+ /* get the hours */
+ JSLL_UI2L(result1,PRMJ_HOUR_SECONDS);
+ JSLL_DIV(result,tsecs,result1);
+ JSLL_L2I(hours,result);
+ JSLL_MUL(result,result,result1);
+ JSLL_SUB(tsecs,tsecs,result);
+
+ /* get minutes */
+ JSLL_UI2L(result1,60);
+ JSLL_DIV(result,tsecs,result1);
+ JSLL_L2I(minutes,result);
+ JSLL_MUL(result,result,result1);
+ JSLL_SUB(tsecs,tsecs,result);
+
+ JSLL_L2I(seconds,tsecs);
+
+ prtm->tm_usec = 0L;
+ prtm->tm_sec = (JSInt8)seconds;
+ prtm->tm_min = (JSInt8)minutes;
+ prtm->tm_hour = (JSInt8)hours;
+ prtm->tm_mday = (JSInt8)mday;
+ prtm->tm_mon = (JSInt8)month;
+ prtm->tm_wday = (JSInt8)wday;
+ prtm->tm_year = (JSInt16)year;
+ prtm->tm_yday = (JSInt16)yday;
+}
diff --git a/src/dom/js/prmjtime.h b/src/dom/js/prmjtime.h
new file mode 100644
index 000000000..6a94a11b1
--- /dev/null
+++ b/src/dom/js/prmjtime.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef prmjtime_h___
+#define prmjtime_h___
+/*
+ * PR date stuff for mocha and java. Placed here temporarily not to break
+ * Navigator and localize changes to mocha.
+ */
+#include <time.h>
+#include "jslong.h"
+#ifdef MOZILLA_CLIENT
+#include "jscompat.h"
+#endif
+
+JS_BEGIN_EXTERN_C
+
+typedef struct PRMJTime PRMJTime;
+
+/*
+ * Broken down form of 64 bit time value.
+ */
+struct PRMJTime {
+ JSInt32 tm_usec; /* microseconds of second (0-999999) */
+ JSInt8 tm_sec; /* seconds of minute (0-59) */
+ JSInt8 tm_min; /* minutes of hour (0-59) */
+ JSInt8 tm_hour; /* hour of day (0-23) */
+ JSInt8 tm_mday; /* day of month (1-31) */
+ JSInt8 tm_mon; /* month of year (0-11) */
+ JSInt8 tm_wday; /* 0=sunday, 1=monday, ... */
+ JSInt16 tm_year; /* absolute year, AD */
+ JSInt16 tm_yday; /* day of year (0 to 365) */
+ JSInt8 tm_isdst; /* non-zero if DST in effect */
+};
+
+/* Some handy constants */
+#define PRMJ_USEC_PER_SEC 1000000L
+#define PRMJ_USEC_PER_MSEC 1000L
+
+/* Return the current local time in micro-seconds */
+extern JSInt64
+PRMJ_Now(void);
+
+/* get the difference between this time zone and gmt timezone in seconds */
+extern JSInt32
+PRMJ_LocalGMTDifference(void);
+
+/* Format a time value into a buffer. Same semantics as strftime() */
+extern size_t
+PRMJ_FormatTime(char *buf, int buflen, char *fmt, PRMJTime *tm);
+
+/* Get the DST offset for the local time passed in */
+extern JSInt64
+PRMJ_DSTOffset(JSInt64 local_time);
+
+JS_END_EXTERN_C
+
+#endif /* prmjtime_h___ */
+
diff --git a/src/dom/js/resource.h b/src/dom/js/resource.h
new file mode 100644
index 000000000..9301810e4
--- /dev/null
+++ b/src/dom/js/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by js3240.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif