From e102c4959cf6605f12394a57d96779fe6687c87e Mon Sep 17 00:00:00 2001 From: ishmal Date: Sat, 8 Mar 2008 21:34:57 +0000 Subject: [PATCH] Begin change from Spidermonkey binding to JVM --- src/dom/js/README.ink | 10 - src/dom/js/fdlibm/e_acos.c | 147 - src/dom/js/fdlibm/e_acosh.c | 105 - src/dom/js/fdlibm/e_asin.c | 156 - src/dom/js/fdlibm/e_atan2.c | 165 - src/dom/js/fdlibm/e_atanh.c | 110 - src/dom/js/fdlibm/e_cosh.c | 133 - src/dom/js/fdlibm/e_exp.c | 202 - src/dom/js/fdlibm/e_fmod.c | 184 - src/dom/js/fdlibm/e_gamma.c | 71 - src/dom/js/fdlibm/e_gamma_r.c | 70 - src/dom/js/fdlibm/e_hypot.c | 173 - src/dom/js/fdlibm/e_j0.c | 524 -- src/dom/js/fdlibm/e_j1.c | 523 -- src/dom/js/fdlibm/e_jn.c | 315 -- src/dom/js/fdlibm/e_lgamma.c | 71 - src/dom/js/fdlibm/e_lgamma_r.c | 347 -- src/dom/js/fdlibm/e_log.c | 184 - src/dom/js/fdlibm/e_log10.c | 134 - src/dom/js/fdlibm/e_pow.c | 386 -- src/dom/js/fdlibm/e_rem_pio2.c | 222 - src/dom/js/fdlibm/e_remainder.c | 120 - src/dom/js/fdlibm/e_scalb.c | 89 - src/dom/js/fdlibm/e_sinh.c | 122 - src/dom/js/fdlibm/e_sqrt.c | 497 -- src/dom/js/fdlibm/fdlibm.h | 273 - src/dom/js/fdlibm/k_cos.c | 135 - src/dom/js/fdlibm/k_rem_pio2.c | 354 -- src/dom/js/fdlibm/k_sin.c | 114 - src/dom/js/fdlibm/k_standard.c | 785 --- src/dom/js/fdlibm/k_tan.c | 170 - src/dom/js/fdlibm/s_asinh.c | 101 - src/dom/js/fdlibm/s_atan.c | 175 - src/dom/js/fdlibm/s_cbrt.c | 133 - src/dom/js/fdlibm/s_ceil.c | 120 - src/dom/js/fdlibm/s_copysign.c | 72 - src/dom/js/fdlibm/s_cos.c | 118 - src/dom/js/fdlibm/s_erf.c | 356 -- src/dom/js/fdlibm/s_expm1.c | 267 - src/dom/js/fdlibm/s_fabs.c | 70 - src/dom/js/fdlibm/s_finite.c | 71 - src/dom/js/fdlibm/s_floor.c | 121 - src/dom/js/fdlibm/s_frexp.c | 99 - src/dom/js/fdlibm/s_ilogb.c | 85 - src/dom/js/fdlibm/s_isnan.c | 74 - src/dom/js/fdlibm/s_ldexp.c | 66 - src/dom/js/fdlibm/s_lib_version.c | 73 - src/dom/js/fdlibm/s_log1p.c | 211 - src/dom/js/fdlibm/s_logb.c | 79 - src/dom/js/fdlibm/s_matherr.c | 64 - src/dom/js/fdlibm/s_modf.c | 132 - src/dom/js/fdlibm/s_nextafter.c | 124 - src/dom/js/fdlibm/s_rint.c | 131 - src/dom/js/fdlibm/s_scalbn.c | 107 - src/dom/js/fdlibm/s_signgam.c | 40 - src/dom/js/fdlibm/s_significand.c | 68 - src/dom/js/fdlibm/s_sin.c | 118 - src/dom/js/fdlibm/s_tan.c | 112 - src/dom/js/fdlibm/s_tanh.c | 122 - src/dom/js/fdlibm/w_acos.c | 78 - src/dom/js/fdlibm/w_acosh.c | 78 - src/dom/js/fdlibm/w_asin.c | 80 - src/dom/js/fdlibm/w_atan2.c | 79 - src/dom/js/fdlibm/w_atanh.c | 81 - src/dom/js/fdlibm/w_cosh.c | 77 - src/dom/js/fdlibm/w_exp.c | 88 - src/dom/js/fdlibm/w_fmod.c | 78 - src/dom/js/fdlibm/w_gamma.c | 85 - src/dom/js/fdlibm/w_gamma_r.c | 81 - src/dom/js/fdlibm/w_hypot.c | 78 - src/dom/js/fdlibm/w_j0.c | 105 - src/dom/js/fdlibm/w_j1.c | 106 - src/dom/js/fdlibm/w_jn.c | 128 - src/dom/js/fdlibm/w_lgamma.c | 85 - src/dom/js/fdlibm/w_lgamma_r.c | 81 - src/dom/js/fdlibm/w_log.c | 78 - src/dom/js/fdlibm/w_log10.c | 81 - src/dom/js/fdlibm/w_pow.c | 99 - src/dom/js/fdlibm/w_remainder.c | 77 - src/dom/js/fdlibm/w_scalb.c | 95 - src/dom/js/fdlibm/w_sinh.c | 77 - src/dom/js/fdlibm/w_sqrt.c | 77 - src/dom/js/js.c | 2632 --------- src/dom/js/js.msg | 290 - src/dom/js/jsapi.c | 4847 ----------------- src/dom/js/jsapi.h | 2027 ------- src/dom/js/jsarena.c | 579 -- src/dom/js/jsarena.h | 313 -- src/dom/js/jsarray.c | 1901 ------- src/dom/js/jsarray.h | 81 - src/dom/js/jsatom.c | 980 ---- src/dom/js/jsatom.h | 468 -- src/dom/js/jsbit.h | 113 - src/dom/js/jsbool.c | 215 - src/dom/js/jsbool.h | 73 - src/dom/js/jsclist.h | 139 - src/dom/js/jscntxt.c | 1073 ---- src/dom/js/jscntxt.h | 803 --- src/dom/js/jscompat.h | 57 - src/dom/js/jsconfig.h | 563 -- src/dom/js/jscpucfg.c | 375 -- src/dom/js/jscpucfg.h | 159 - src/dom/js/jsdate.c | 2386 --------- src/dom/js/jsdate.h | 118 - src/dom/js/jsdbgapi.c | 1405 ----- src/dom/js/jsdbgapi.h | 406 -- src/dom/js/jsdhash.c | 767 --- src/dom/js/jsdhash.h | 579 -- src/dom/js/jsdtoa.c | 3126 ----------- src/dom/js/jsdtoa.h | 130 - src/dom/js/jsemit.c | 5399 ------------------- src/dom/js/jsemit.h | 592 -- src/dom/js/jsexn.c | 1186 ----- src/dom/js/jsexn.h | 102 - src/dom/js/jsfile.c | 2720 ---------- src/dom/js/jsfile.h | 50 - src/dom/js/jsfile.msg | 90 - src/dom/js/jsfun.c | 2258 -------- src/dom/js/jsfun.h | 164 - src/dom/js/jsgc.c | 1989 ------- src/dom/js/jsgc.h | 272 - src/dom/js/jshash.c | 471 -- src/dom/js/jshash.h | 152 - src/dom/js/jsinterp.c | 5564 ------------------- src/dom/js/jsinterp.h | 322 -- src/dom/js/jslibmath.h | 290 - src/dom/js/jslock.c | 1261 ----- src/dom/js/jslock.h | 261 - src/dom/js/jslocko.asm | 60 - src/dom/js/jslog2.c | 83 - src/dom/js/jslong.c | 281 - src/dom/js/jslong.h | 437 -- src/dom/js/jsmath.c | 479 -- src/dom/js/jsmath.h | 55 - src/dom/js/jsnum.c | 1145 ---- src/dom/js/jsnum.h | 268 - src/dom/js/jsobj.c | 4646 ---------------- src/dom/js/jsobj.h | 527 -- src/dom/js/jsopcode.c | 3167 ----------- src/dom/js/jsopcode.h | 301 -- src/dom/js/jsopcode.tbl | 396 -- src/dom/js/jsosdep.h | 112 - src/dom/js/jsotypes.h | 202 - src/dom/js/jsparse.c | 4880 ----------------- src/dom/js/jsparse.h | 414 -- src/dom/js/jsprf.c | 1264 ----- src/dom/js/jsprf.h | 150 - src/dom/js/jsprvtd.h | 203 - src/dom/js/jspubtd.h | 618 --- src/dom/js/jsregexp.c | 4180 --------------- src/dom/js/jsregexp.h | 183 - src/dom/js/jsscan.c | 2170 -------- src/dom/js/jsscan.h | 363 -- src/dom/js/jsscope.c | 1702 ------ src/dom/js/jsscope.h | 394 -- src/dom/js/jsscript.c | 1490 ------ src/dom/js/jsscript.h | 209 - src/dom/js/jsshell.msg | 50 - src/dom/js/jsstddef.h | 83 - src/dom/js/jsstr.c | 4868 ----------------- src/dom/js/jsstr.h | 482 -- src/dom/js/jstypes.h | 421 -- src/dom/js/jsutil.c | 192 - src/dom/js/jsutil.h | 94 - src/dom/js/jsxdrapi.c | 686 --- src/dom/js/jsxdrapi.h | 193 - src/dom/js/jsxml.c | 8295 ----------------------------- src/dom/js/jsxml.h | 329 -- src/dom/js/prmjtime.c | 440 -- src/dom/js/prmjtime.h | 95 - src/dom/js/resource.h | 15 - src/dom/jsdombind.cpp | 3959 -------------- src/dom/jsdombind.h | 163 - src/dom/jsengine.cpp | 265 - src/dom/jsengine.h | 178 - 175 files changed, 113107 deletions(-) delete mode 100644 src/dom/js/README.ink delete mode 100644 src/dom/js/fdlibm/e_acos.c delete mode 100644 src/dom/js/fdlibm/e_acosh.c delete mode 100644 src/dom/js/fdlibm/e_asin.c delete mode 100644 src/dom/js/fdlibm/e_atan2.c delete mode 100644 src/dom/js/fdlibm/e_atanh.c delete mode 100644 src/dom/js/fdlibm/e_cosh.c delete mode 100644 src/dom/js/fdlibm/e_exp.c delete mode 100644 src/dom/js/fdlibm/e_fmod.c delete mode 100644 src/dom/js/fdlibm/e_gamma.c delete mode 100644 src/dom/js/fdlibm/e_gamma_r.c delete mode 100644 src/dom/js/fdlibm/e_hypot.c delete mode 100644 src/dom/js/fdlibm/e_j0.c delete mode 100644 src/dom/js/fdlibm/e_j1.c delete mode 100644 src/dom/js/fdlibm/e_jn.c delete mode 100644 src/dom/js/fdlibm/e_lgamma.c delete mode 100644 src/dom/js/fdlibm/e_lgamma_r.c delete mode 100644 src/dom/js/fdlibm/e_log.c delete mode 100644 src/dom/js/fdlibm/e_log10.c delete mode 100644 src/dom/js/fdlibm/e_pow.c delete mode 100644 src/dom/js/fdlibm/e_rem_pio2.c delete mode 100644 src/dom/js/fdlibm/e_remainder.c delete mode 100644 src/dom/js/fdlibm/e_scalb.c delete mode 100644 src/dom/js/fdlibm/e_sinh.c delete mode 100644 src/dom/js/fdlibm/e_sqrt.c delete mode 100644 src/dom/js/fdlibm/fdlibm.h delete mode 100644 src/dom/js/fdlibm/k_cos.c delete mode 100644 src/dom/js/fdlibm/k_rem_pio2.c delete mode 100644 src/dom/js/fdlibm/k_sin.c delete mode 100644 src/dom/js/fdlibm/k_standard.c delete mode 100644 src/dom/js/fdlibm/k_tan.c delete mode 100644 src/dom/js/fdlibm/s_asinh.c delete mode 100644 src/dom/js/fdlibm/s_atan.c delete mode 100644 src/dom/js/fdlibm/s_cbrt.c delete mode 100644 src/dom/js/fdlibm/s_ceil.c delete mode 100644 src/dom/js/fdlibm/s_copysign.c delete mode 100644 src/dom/js/fdlibm/s_cos.c delete mode 100644 src/dom/js/fdlibm/s_erf.c delete mode 100644 src/dom/js/fdlibm/s_expm1.c delete mode 100644 src/dom/js/fdlibm/s_fabs.c delete mode 100644 src/dom/js/fdlibm/s_finite.c delete mode 100644 src/dom/js/fdlibm/s_floor.c delete mode 100644 src/dom/js/fdlibm/s_frexp.c delete mode 100644 src/dom/js/fdlibm/s_ilogb.c delete mode 100644 src/dom/js/fdlibm/s_isnan.c delete mode 100644 src/dom/js/fdlibm/s_ldexp.c delete mode 100644 src/dom/js/fdlibm/s_lib_version.c delete mode 100644 src/dom/js/fdlibm/s_log1p.c delete mode 100644 src/dom/js/fdlibm/s_logb.c delete mode 100644 src/dom/js/fdlibm/s_matherr.c delete mode 100644 src/dom/js/fdlibm/s_modf.c delete mode 100644 src/dom/js/fdlibm/s_nextafter.c delete mode 100644 src/dom/js/fdlibm/s_rint.c delete mode 100644 src/dom/js/fdlibm/s_scalbn.c delete mode 100644 src/dom/js/fdlibm/s_signgam.c delete mode 100644 src/dom/js/fdlibm/s_significand.c delete mode 100644 src/dom/js/fdlibm/s_sin.c delete mode 100644 src/dom/js/fdlibm/s_tan.c delete mode 100644 src/dom/js/fdlibm/s_tanh.c delete mode 100644 src/dom/js/fdlibm/w_acos.c delete mode 100644 src/dom/js/fdlibm/w_acosh.c delete mode 100644 src/dom/js/fdlibm/w_asin.c delete mode 100644 src/dom/js/fdlibm/w_atan2.c delete mode 100644 src/dom/js/fdlibm/w_atanh.c delete mode 100644 src/dom/js/fdlibm/w_cosh.c delete mode 100644 src/dom/js/fdlibm/w_exp.c delete mode 100644 src/dom/js/fdlibm/w_fmod.c delete mode 100644 src/dom/js/fdlibm/w_gamma.c delete mode 100644 src/dom/js/fdlibm/w_gamma_r.c delete mode 100644 src/dom/js/fdlibm/w_hypot.c delete mode 100644 src/dom/js/fdlibm/w_j0.c delete mode 100644 src/dom/js/fdlibm/w_j1.c delete mode 100644 src/dom/js/fdlibm/w_jn.c delete mode 100644 src/dom/js/fdlibm/w_lgamma.c delete mode 100644 src/dom/js/fdlibm/w_lgamma_r.c delete mode 100644 src/dom/js/fdlibm/w_log.c delete mode 100644 src/dom/js/fdlibm/w_log10.c delete mode 100644 src/dom/js/fdlibm/w_pow.c delete mode 100644 src/dom/js/fdlibm/w_remainder.c delete mode 100644 src/dom/js/fdlibm/w_scalb.c delete mode 100644 src/dom/js/fdlibm/w_sinh.c delete mode 100644 src/dom/js/fdlibm/w_sqrt.c delete mode 100644 src/dom/js/js.c delete mode 100644 src/dom/js/js.msg delete mode 100644 src/dom/js/jsapi.c delete mode 100644 src/dom/js/jsapi.h delete mode 100644 src/dom/js/jsarena.c delete mode 100644 src/dom/js/jsarena.h delete mode 100644 src/dom/js/jsarray.c delete mode 100644 src/dom/js/jsarray.h delete mode 100644 src/dom/js/jsatom.c delete mode 100644 src/dom/js/jsatom.h delete mode 100644 src/dom/js/jsbit.h delete mode 100644 src/dom/js/jsbool.c delete mode 100644 src/dom/js/jsbool.h delete mode 100644 src/dom/js/jsclist.h delete mode 100644 src/dom/js/jscntxt.c delete mode 100644 src/dom/js/jscntxt.h delete mode 100644 src/dom/js/jscompat.h delete mode 100644 src/dom/js/jsconfig.h delete mode 100644 src/dom/js/jscpucfg.c delete mode 100644 src/dom/js/jscpucfg.h delete mode 100644 src/dom/js/jsdate.c delete mode 100644 src/dom/js/jsdate.h delete mode 100644 src/dom/js/jsdbgapi.c delete mode 100644 src/dom/js/jsdbgapi.h delete mode 100644 src/dom/js/jsdhash.c delete mode 100644 src/dom/js/jsdhash.h delete mode 100644 src/dom/js/jsdtoa.c delete mode 100644 src/dom/js/jsdtoa.h delete mode 100644 src/dom/js/jsemit.c delete mode 100644 src/dom/js/jsemit.h delete mode 100644 src/dom/js/jsexn.c delete mode 100644 src/dom/js/jsexn.h delete mode 100644 src/dom/js/jsfile.c delete mode 100644 src/dom/js/jsfile.h delete mode 100644 src/dom/js/jsfile.msg delete mode 100644 src/dom/js/jsfun.c delete mode 100644 src/dom/js/jsfun.h delete mode 100644 src/dom/js/jsgc.c delete mode 100644 src/dom/js/jsgc.h delete mode 100644 src/dom/js/jshash.c delete mode 100644 src/dom/js/jshash.h delete mode 100644 src/dom/js/jsinterp.c delete mode 100644 src/dom/js/jsinterp.h delete mode 100644 src/dom/js/jslibmath.h delete mode 100644 src/dom/js/jslock.c delete mode 100644 src/dom/js/jslock.h delete mode 100644 src/dom/js/jslocko.asm delete mode 100644 src/dom/js/jslog2.c delete mode 100644 src/dom/js/jslong.c delete mode 100644 src/dom/js/jslong.h delete mode 100644 src/dom/js/jsmath.c delete mode 100644 src/dom/js/jsmath.h delete mode 100644 src/dom/js/jsnum.c delete mode 100644 src/dom/js/jsnum.h delete mode 100644 src/dom/js/jsobj.c delete mode 100644 src/dom/js/jsobj.h delete mode 100644 src/dom/js/jsopcode.c delete mode 100644 src/dom/js/jsopcode.h delete mode 100644 src/dom/js/jsopcode.tbl delete mode 100644 src/dom/js/jsosdep.h delete mode 100644 src/dom/js/jsotypes.h delete mode 100644 src/dom/js/jsparse.c delete mode 100644 src/dom/js/jsparse.h delete mode 100644 src/dom/js/jsprf.c delete mode 100644 src/dom/js/jsprf.h delete mode 100644 src/dom/js/jsprvtd.h delete mode 100644 src/dom/js/jspubtd.h delete mode 100644 src/dom/js/jsregexp.c delete mode 100644 src/dom/js/jsregexp.h delete mode 100644 src/dom/js/jsscan.c delete mode 100644 src/dom/js/jsscan.h delete mode 100644 src/dom/js/jsscope.c delete mode 100644 src/dom/js/jsscope.h delete mode 100644 src/dom/js/jsscript.c delete mode 100644 src/dom/js/jsscript.h delete mode 100644 src/dom/js/jsshell.msg delete mode 100644 src/dom/js/jsstddef.h delete mode 100644 src/dom/js/jsstr.c delete mode 100644 src/dom/js/jsstr.h delete mode 100644 src/dom/js/jstypes.h delete mode 100644 src/dom/js/jsutil.c delete mode 100644 src/dom/js/jsutil.h delete mode 100644 src/dom/js/jsxdrapi.c delete mode 100644 src/dom/js/jsxdrapi.h delete mode 100644 src/dom/js/jsxml.c delete mode 100644 src/dom/js/jsxml.h delete mode 100644 src/dom/js/prmjtime.c delete mode 100644 src/dom/js/prmjtime.h delete mode 100644 src/dom/js/resource.h delete mode 100644 src/dom/jsdombind.cpp delete mode 100644 src/dom/jsdombind.h delete mode 100644 src/dom/jsengine.cpp delete mode 100644 src/dom/jsengine.h diff --git a/src/dom/js/README.ink b/src/dom/js/README.ink deleted file mode 100644 index bbb53278c..000000000 --- a/src/dom/js/README.ink +++ /dev/null @@ -1,10 +0,0 @@ -README for Inkscape's JS Embedding - -Note that we edited jstypes.h to -#if defined(_WIN32) && !defined(__MWERKS__) && !defined(__GNUC__) - -So that we can statically link JS to Inkscape on MinGW. - - -bob -6 Mar 07 diff --git a/src/dom/js/fdlibm/e_acos.c b/src/dom/js/fdlibm/e_acos.c deleted file mode 100644 index a07c1eebc..000000000 --- a/src/dom/js/fdlibm/e_acos.c +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 725cceefb..000000000 --- a/src/dom/js/fdlibm/e_acosh.c +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- 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 { /* 10.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 deleted file mode 100644 index 9c9a2c01f..000000000 --- a/src/dom/js/fdlibm/e_atan2.c +++ /dev/null @@ -1,165 +0,0 @@ -/* -*- 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 deleted file mode 100644 index dc4a90c8e..000000000 --- a/src/dom/js/fdlibm/e_atanh.c +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 4f8d4f769..000000000 --- a/src/dom/js/fdlibm/e_cosh.c +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- 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 deleted file mode 100644 index ad9cec124..000000000 --- a/src/dom/js/fdlibm/e_exp.c +++ /dev/null @@ -1,202 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 7b5ce780f..000000000 --- a/src/dom/js/fdlibm/e_fmod.c +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- 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>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<>(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<>(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>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=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 deleted file mode 100644 index a34faa32c..000000000 --- a/src/dom/js/fdlibm/e_gamma.c +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- 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 deleted file mode 100644 index f10e32e36..000000000 --- a/src/dom/js/fdlibm/e_gamma_r.c +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 390023087..000000000 --- a/src/dom/js/fdlibm/e_hypot.c +++ /dev/null @@ -1,173 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 078e09641..000000000 --- a/src/dom/js/fdlibm/e_j0.c +++ /dev/null @@ -1,524 +0,0 @@ -/* -*- 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)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)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 deleted file mode 100644 index 8982ac86a..000000000 --- a/src/dom/js/fdlibm/e_j1.c +++ /dev/null @@ -1,523 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 2b61b4439..000000000 --- a/src/dom/js/fdlibm/e_jn.c +++ /dev/null @@ -1,315 +0,0 @@ -/* -*- 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 nx, 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;i33) /* 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;i0) return b; else return -b; -} diff --git a/src/dom/js/fdlibm/e_lgamma.c b/src/dom/js/fdlibm/e_lgamma.c deleted file mode 100644 index beb3bd932..000000000 --- a/src/dom/js/fdlibm/e_lgamma.c +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- 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 deleted file mode 100644 index df92e7a26..000000000 --- a/src/dom/js/fdlibm/e_lgamma_r.c +++ /dev/null @@ -1,347 +0,0 @@ -/* -*- 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=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 deleted file mode 100644 index 8645d6efd..000000000 --- a/src/dom/js/fdlibm/e_log.c +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 5f88f4b4c..000000000 --- a/src/dom/js/fdlibm/e_log10.c +++ /dev/null @@ -1,134 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 18c8d0695..000000000 --- a/src/dom/js/fdlibm/e_pow.c +++ /dev/null @@ -1,386 +0,0 @@ -/* -*- 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|>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 deleted file mode 100644 index c9d261875..000000000 --- a/src/dom/js/fdlibm/e_rem_pio2.c +++ /dev/null @@ -1,222 +0,0 @@ -/* -*- 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 = 0; - double 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 deleted file mode 100644 index de40f0c2a..000000000 --- a/src/dom/js/fdlibm/e_remainder.c +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 621704ea0..000000000 --- a/src/dom/js/fdlibm/e_scalb.c +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 98ab9b5a3..000000000 --- a/src/dom/js/fdlibm/e_sinh.c +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 91802839b..000000000 --- a/src/dom/js/fdlibm/e_sqrt.c +++ /dev/null @@ -1,497 +0,0 @@ -/* -*- 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>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+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 deleted file mode 100644 index e623be56e..000000000 --- a/src/dom/js/fdlibm/fdlibm.h +++ /dev/null @@ -1,273 +0,0 @@ -/* -*- 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__) || defined(__x86_64__) || defined(__ia64) || (defined(__mips) && defined(__MIPSEL__))) -#define __LITTLE_ENDIAN -#endif - -/* End here. The rest is the standard file. */ - -#ifdef SOLARIS /* 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 - * (one may replace the following line by "#include ") - */ - -#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 deleted file mode 100644 index 1d18c8034..000000000 --- a/src/dom/js/fdlibm/k_cos.c +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- 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 qx = 0; - double a,hz,z,r; - 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 deleted file mode 100644 index d261e190a..000000000 --- a/src/dom/js/fdlibm/k_rem_pio2.c +++ /dev/null @@ -1,354 +0,0 @@ -/* -*- 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;i0) { /* 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 deleted file mode 100644 index d2bdabd6d..000000000 --- a/src/dom/js/fdlibm/k_sin.c +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 720109c9d..000000000 --- a/src/dom/js/fdlibm/k_standard.c +++ /dev/null @@ -1,785 +0,0 @@ -/* -*- 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 -#endif - - -#ifndef _USE_WRITE -#include /* fputs(), stderr */ -#define WRITE2(u,v) fputs(u, stderr) -#else /* !defined(_USE_WRITE) */ -#include /* 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(xzero) ? 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 deleted file mode 100644 index 1e7681b88..000000000 --- a/src/dom/js/fdlibm/k_tan.c +++ /dev/null @@ -1,170 +0,0 @@ -/* -*- 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 deleted file mode 100644 index fdf70a91c..000000000 --- a/src/dom/js/fdlibm/s_asinh.c +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 99a00c686..000000000 --- a/src/dom/js/fdlibm/s_atan.c +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 4aed19b1b..000000000 --- a/src/dom/js/fdlibm/s_cbrt.c +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 826bcac6c..000000000 --- a/src/dom/js/fdlibm/s_ceil.c +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- 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=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 deleted file mode 100644 index 6eae8de3b..000000000 --- a/src/dom/js/fdlibm/s_erf.c +++ /dev/null @@ -1,356 +0,0 @@ -/* -*- 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 >= 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 deleted file mode 100644 index 578d2e144..000000000 --- a/src/dom/js/fdlibm/s_expm1.c +++ /dev/null @@ -1,267 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 6b029da10..000000000 --- a/src/dom/js/fdlibm/s_fabs.c +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 4a0a4d3c6..000000000 --- a/src/dom/js/fdlibm/s_finite.c +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 6c23495f0..000000000 --- a/src/dom/js/fdlibm/s_floor.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- 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=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 deleted file mode 100644 index f769781a6..000000000 --- a/src/dom/js/fdlibm/s_ilogb.c +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 52f8759c7..000000000 --- a/src/dom/js/fdlibm/s_isnan.c +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 9475520d4..000000000 --- a/src/dom/js/fdlibm/s_ldexp.c +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- 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 - -#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 deleted file mode 100644 index 2ccf67d51..000000000 --- a/src/dom/js/fdlibm/s_lib_version.c +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 1840156b1..000000000 --- a/src/dom/js/fdlibm/s_log1p.c +++ /dev/null @@ -1,211 +0,0 @@ -/* -*- 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= 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 deleted file mode 100644 index f885c4dc3..000000000 --- a/src/dom/js/fdlibm/s_logb.c +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- 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 deleted file mode 100644 index cd99ca88f..000000000 --- a/src/dom/js/fdlibm/s_matherr.c +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 3b182bd3b..000000000 --- a/src/dom/js/fdlibm/s_modf.c +++ /dev/null @@ -1,132 +0,0 @@ -/* -*- 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 deleted file mode 100644 index f71c5c835..000000000 --- a/src/dom/js/fdlibm/s_nextafter.c +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 3c4fab6d9..000000000 --- a/src/dom/js/fdlibm/s_rint.c +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 3deeaa305..000000000 --- a/src/dom/js/fdlibm/s_scalbn.c +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 4eb8ce72f..000000000 --- a/src/dom/js/fdlibm/s_signgam.c +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 2e1c0b28f..000000000 --- a/src/dom/js/fdlibm/s_significand.c +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 8bbc5c62d..000000000 --- a/src/dom/js/fdlibm/s_sin.c +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- 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 deleted file mode 100644 index ded36c1d7..000000000 --- a/src/dom/js/fdlibm/s_tan.c +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- 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 deleted file mode 100644 index aa6809f85..000000000 --- a/src/dom/js/fdlibm/s_tanh.c +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 872c81d20..000000000 --- a/src/dom/js/fdlibm/w_acos.c +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 745d402ea..000000000 --- a/src/dom/js/fdlibm/w_acosh.c +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 18aaefde9..000000000 --- a/src/dom/js/fdlibm/w_asin.c +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 8cfa4bbbd..000000000 --- a/src/dom/js/fdlibm/w_atan2.c +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 6ba52d1e2..000000000 --- a/src/dom/js/fdlibm/w_atanh.c +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 146449e02..000000000 --- a/src/dom/js/fdlibm/w_cosh.c +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- 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 deleted file mode 100644 index f5dea0b01..000000000 --- a/src/dom/js/fdlibm/w_exp.c +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- 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(xX_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 deleted file mode 100644 index 86a506bc2..000000000 --- a/src/dom/js/fdlibm/w_j1.c +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 6926b0da8..000000000 --- a/src/dom/js/fdlibm/w_jn.c +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- 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 nx, 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 deleted file mode 100644 index f7576e892..000000000 --- a/src/dom/js/fdlibm/w_lgamma.c +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- 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 deleted file mode 100644 index ba2ad5933..000000000 --- a/src/dom/js/fdlibm/w_lgamma_r.c +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 7e358fcf1..000000000 --- a/src/dom/js/fdlibm/w_log.c +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 6b298b236..000000000 --- a/src/dom/js/fdlibm/w_log10.c +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 3d2c15ad3..000000000 --- a/src/dom/js/fdlibm/w_pow.c +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 25d1ba171..000000000 --- a/src/dom/js/fdlibm/w_remainder.c +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 35c16a500..000000000 --- a/src/dom/js/fdlibm/w_scalb.c +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- 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 - -#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 deleted file mode 100644 index 8b04ecb7f..000000000 --- a/src/dom/js/fdlibm/w_sinh.c +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 462d776f8..000000000 --- a/src/dom/js/fdlibm/w_sqrt.c +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- 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 deleted file mode 100644 index b39616670..000000000 --- a/src/dom/js/js.c +++ /dev/null @@ -1,2632 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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 -#include -#include -#include -#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 -#include -#include -#endif - -#if defined(XP_WIN) || defined(XP_OS2) -#include /* for isatty() */ -#endif - -typedef enum JSShellExitCode { - EXITCODE_RUNTIME_ERROR = 3, - EXITCODE_FILE_NOT_FOUND = 4, - EXITCODE_OUT_OF_MEMORY = 5 -} JSShellExitCode; - -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 JSDEBUGGER -static JSDContext *_jsdc; -#ifdef JSDEBUGGER_JAVA_UI -static JSDJContext *_jsdjc; -#endif /* JSDEBUGGER_JAVA_UI */ -#endif /* JSDEBUGGER */ - -static JSBool reportWarnings = JS_TRUE; -static JSBool compileOnly = JS_FALSE; - -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); - 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) { - if (!compileOnly) - (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), "typein", - startline); - if (script) { - if (!compileOnly) { - 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 [-PswWxC] [-b branchlimit] [-c stackchunksize] [-v version] [-f scriptfile] [-e script] [-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) { - if (script->filename) - fprintf(gErrFile, "%s:", script->filename); - fprintf(gErrFile, "%u: script branch callback (%u callbacks)\n", - script->lineno, gBranchLimit); - } else { - fprintf(gErrFile, "native branch callback (%u callbacks)\n", - gBranchLimit); - } - gBranchCount = 0; - return JS_FALSE; - } - if ((gBranchCount & 0x3fff) == 1) - JS_MaybeGC(cx); - 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 'e': - case 'v': - case 'S': - ++i; - break; - default:; - } - } - - /* - * 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 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 'x': - JS_ToggleOptions(cx, JSOPTION_XML); - 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); - JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK); - 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 the test - * harness. Just execute foo.js for now. - */ - isInteractive = JS_FALSE; - break; - - case 'e': - { - jsval rval; - - if (++i == argc) { - return usage(); - } - - /* Pass a filename of -e to imitate PERL */ - JS_EvaluateScript(cx, obj, argv[i], strlen(argv[i]), - "-e", 1, &rval); - - isInteractive = JS_FALSE; - break; - - } - case 'C': - compileOnly = JS_TRUE; - 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}, - {"atline", JSOPTION_ATLINE}, - {"xml", JSOPTION_XML}, - {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; - uint32 oldopts; - - 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); - oldopts = JS_GetOptions(cx); - JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO); - script = JS_CompileFile(cx, obj, filename); - if (!script) { - ok = JS_FALSE; - } else { - ok = !compileOnly - ? JS_ExecuteScript(cx, obj, script, &result) - : JS_TRUE; - JS_DestroyScript(cx, script); - } - JS_SetOptions(cx, oldopts); - JS_SetErrorReporter(cx, older); - if (!ok) - return JS_FALSE; - } - - return JS_TRUE; -} - -/* - * function readline() - * Provides a hook for scripts to read a line from stdin. - */ -static JSBool -ReadLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ -#define BUFSIZE 256 - FILE *from; - char *buf, *tmp; - size_t bufsize, buflength, gotlength; - JSString *str; - - from = stdin; - buflength = 0; - bufsize = BUFSIZE; - buf = JS_malloc(cx, bufsize); - if (!buf) - return JS_FALSE; - - while ((gotlength = - js_fgets(buf + buflength, bufsize - buflength, from)) > 0) { - buflength += gotlength; - - /* Are we done? */ - if (buf[buflength - 1] == '\n') { - buf[buflength - 1] = '\0'; - break; - } - - /* Else, grow our buffer for another pass. */ - tmp = JS_realloc(cx, buf, bufsize * 2); - if (!tmp) { - JS_free(cx, buf); - return JS_FALSE; - } - - bufsize *= 2; - buf = tmp; - } - - /* Treat the empty string specially. */ - if (buflength == 0) { - *rval = JS_GetEmptyStringValue(cx); - JS_free(cx, buf); - return JS_TRUE; - } - - /* Shrink the buffer to the real size. */ - tmp = JS_realloc(cx, buf, buflength); - if (!tmp) { - JS_free(cx, buf); - return JS_FALSE; - } - - buf = tmp; - - /* - * Turn buf into a JSString. Note that buflength includes the trailing null - * character. - */ - str = JS_NewString(cx, buf, buflength - 1); - if (!str) { - JS_free(cx, buf); - return JS_FALSE; - } - - *rval = STRING_TO_JSVAL(str); - 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; -} - -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_PRIMITIVE(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(fun); - } - return script; -} - -static JSBool -GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, - int32 *ip) -{ - jsval v; - uintN intarg; - JSScript *script; - - *scriptp = cx->fp->down->script; - *ip = 0; - if (argc != 0) { - v = argv[0]; - intarg = 0; - if (!JSVAL_IS_PRIMITIVE(v) && - (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass || - JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass)) { - script = ValueToScript(cx, v); - 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'); - } - } - - if (!js_Disassemble(cx, script, lines, stdout)) - return JS_FALSE; - 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 (JSID_IS_INT(sprop->id)) { - fprintf(fp, " [%ld]", (long)JSVAL_TO_INT(sprop->id)); - } else if (JSID_IS_ATOM(sprop->id)) { - JSAtom *atom = JSID_TO_ATOM(sprop->id); - fprintf(fp, " \"%s\"", js_AtomToPrintableString(cx, atom)); - } else { - jsval v = OBJECT_TO_JSVAL(JSID_TO_OBJECT(sprop->id)); - fprintf(fp, " \"%s\"", js_ValueToPrintableString(cx, v)); - } - -#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, ATOM_TO_JSID(atom), &obj, &obj2, &prop)) - return JS_FALSE; - if (prop) { - OBJ_DROP_PROPERTY(cx, obj2, prop); - if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_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, ATOM_TO_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, ATOM_TO_JSID(atom), prop, &attrs); - if (ok) { - attrs |= JSPROP_EXPORTED; - ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs); - } - OBJ_DROP_PROPERTY(cx, obj2, prop); - } - return ok; -} -#endif - -#ifdef TEST_CVTARGS -#include - -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 - -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 JSBool -GetPDA(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSObject *vobj, *aobj, *pdobj; - JSBool ok; - JSPropertyDescArray pda; - JSPropertyDesc *pd; - uint32 i; - jsval v; - - if (!JS_ValueToObject(cx, argv[0], &vobj)) - return JS_FALSE; - if (!vobj) - return JS_TRUE; - - aobj = JS_NewArrayObject(cx, 0, NULL); - if (!aobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(aobj); - - ok = JS_GetPropertyDescArray(cx, vobj, &pda); - if (!ok) - return JS_FALSE; - pd = pda.array; - for (i = 0; i < pda.length; i++) { - pdobj = JS_NewObject(cx, NULL, NULL, NULL); - if (!pdobj) { - ok = JS_FALSE; - break; - } - - ok = JS_SetProperty(cx, pdobj, "id", &pd->id) && - JS_SetProperty(cx, pdobj, "value", &pd->value) && - (v = INT_TO_JSVAL(pd->flags), - JS_SetProperty(cx, pdobj, "flags", &v)) && - (v = INT_TO_JSVAL(pd->slot), - JS_SetProperty(cx, pdobj, "slot", &v)) && - JS_SetProperty(cx, pdobj, "alias", &pd->alias); - if (!ok) - break; - - v = OBJECT_TO_JSVAL(pdobj); - ok = JS_SetElement(cx, aobj, i, &v); - if (!ok) - break; - } - JS_PutPropertyDescArray(cx, &pda); - return ok; -} - -static JSBool -GetSLX(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSScript *script; - - script = ValueToScript(cx, argv[0]); - if (!script) - return JS_FALSE; - *rval = INT_TO_JSVAL(js_GetScriptLineExtent(script)); - return JS_TRUE; -} - -static JSBool -ToInt32(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - int32 i; - - if (!JS_ValueToInt32(cx, argv[0], &i)) - return JS_FALSE; - return JS_NewNumberValue(cx, i, rval); -} - -static JSBool -StringsAreUtf8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - *rval = JS_StringsAreUTF8 () ? JSVAL_TRUE : JSVAL_FALSE; - return JS_TRUE; -} - -static const char* badUtf8 = "...\xC0..."; -static const char* bigUtf8 = "...\xFB\xBF\xBF\xBF\xBF..."; -static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 }; - -static JSBool -TestUtf8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - intN mode = 1; - jschar chars[20]; - size_t charsLength = 5; - char bytes[20]; - size_t bytesLength = 20; - if (argc && !JS_ValueToInt32(cx, *argv, &mode)) - return JS_FALSE; - - /* The following throw errors if compiled with UTF-8. */ - switch (mode) { - /* mode 1: malformed UTF-8 string. */ - case 1: - JS_NewStringCopyZ(cx, badUtf8); - break; - /* mode 2: big UTF-8 character. */ - case 2: - JS_NewStringCopyZ(cx, bigUtf8); - break; - /* mode 3: bad surrogate character. */ - case 3: - JS_EncodeCharacters(cx, badSurrogate, 6, bytes, &bytesLength); - break; - /* mode 4: use a too small buffer. */ - case 4: - JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength); - break; - default: - JS_ReportError(cx, "invalid mode parameter"); - return JS_FALSE; - } - return !JS_IsExceptionPending (cx); -} - -static JSFunctionSpec shell_functions[] = { - {"version", Version, 0}, - {"options", Options, 0}, - {"load", Load, 1}, - {"readline", ReadLine, 0}, - {"print", Print, 0}, - {"help", Help, 0}, - {"quit", Quit, 0}, - {"gc", GC, 0}, - {"trap", Trap, 3}, - {"untrap", Untrap, 2}, - {"line2pc", LineToPC, 0}, - {"pc2line", PCToLine, 0}, - {"stringsAreUtf8", StringsAreUtf8, 0}, - {"testUtf8", TestUtf8, 1}, -#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}, - {"getpda", GetPDA, 1}, - {"getslx", GetSLX, 1}, - {"toint32", ToInt32, 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", - "readline() Read a single line from stdin", - "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", - "stringsAreUTF8() Check if strings are UTF-8 encoded", - "testUTF8(mode) Perform UTF-8 tests (modes are 1 to 4)", -#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", - "getpda(obj) Get the property descriptors for obj", - "getslx(obj) Get script line extent", - "toint32(n) Testing hook for JS_ValueToInt32", - 0 -}; - -static void -ShowHelpHeader(void) -{ - fprintf(gOutFile, "%-14s %-22s %s\n", "Command", "Usage", "Description"); - fprintf(gOutFile, "%-14s %-22s %s\n", "=======", "=====", "==========="); -} - -static void -ShowHelpForCommand(uintN n) -{ - fprintf(gOutFile, "%-14.14s %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 JSBool -its_bindMethod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - char *name; - JSObject *method; - - if (!JS_ConvertArguments(cx, argc, argv, "so", &name, &method)) - return JS_FALSE; - - *rval = OBJECT_TO_JSVAL(method); - - if (JS_TypeOfValue(cx, *rval) != JSTYPE_FUNCTION) { - JSString *valstr = JS_ValueToString(cx, *rval); - if (valstr) { - JS_ReportError(cx, "can't bind method %s to non-callable object %s", - name, JS_GetStringBytes(valstr)); - } - return JS_FALSE; - } - - if (!JS_DefineProperty(cx, obj, name, *rval, NULL, NULL, JSPROP_ENUMERATE)) - return JS_FALSE; - - return JS_SetParent(cx, method, obj); -} - -static JSFunctionSpec its_methods[] = { - {"item", its_item, 0}, - {"bindMethod", its_bindMethod, 2}, - {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, uintN flags, - JSObject **objp) -{ - if (its_noisy) { - fprintf(gOutFile, "resolving its property %s, flags {%s,%s,%s}\n", - JS_GetStringBytes(JS_ValueToString(cx, id)), - (flags & JSRESOLVE_QUALIFIED) ? "qualified" : "", - (flags & JSRESOLVE_ASSIGNING) ? "assigning" : "", - (flags & JSRESOLVE_DETECTING) ? "detecting" : ""); - } - 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", JSCLASS_NEW_RESOLVE, - its_addProperty, its_delProperty, its_getProperty, its_setProperty, - its_enumerate, (JSResolveOp)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)) { - if (report->errorNumber == JSMSG_OUT_OF_MEMORY) { - gExitCode = EXITCODE_OUT_OF_MEMORY; - } else { - 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 , 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 -}; - -#ifdef NARCISSUS - -static JSBool -defineProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSString *str; - jsval value; - JSBool dontDelete, readOnly, dontEnum; - const jschar *chars; - size_t length; - uintN attrs; - - dontDelete = readOnly = dontEnum = JS_FALSE; - if (!JS_ConvertArguments(cx, argc, argv, "Sv/bbb", - &str, &value, &dontDelete, &readOnly, &dontEnum)) { - return JS_FALSE; - } - chars = JS_GetStringChars(str); - length = JS_GetStringLength(str); - attrs = dontEnum ? 0 : JSPROP_ENUMERATE; - if (dontDelete) - attrs |= JSPROP_PERMANENT; - if (readOnly) - attrs |= JSPROP_READONLY; - return JS_DefineUCProperty(cx, obj, chars, length, value, NULL, NULL, - attrs); -} - -static JSBool -Evaluate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - /* function evaluate(source, filename, lineno) { ... } */ - JSString *source; - const char *filename = ""; - jsuint lineno = 0; - uint32 oldopts; - JSBool ok; - - if (argc == 0) { - *rval = JSVAL_VOID; - return JS_TRUE; - } - - if (!JS_ConvertArguments(cx, argc, argv, "S/su", - &source, &filename, &lineno)) { - return JS_FALSE; - } - - oldopts = JS_GetOptions(cx); - JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO); - ok = JS_EvaluateUCScript(cx, obj, JS_GetStringChars(source), - JS_GetStringLength(source), filename, - lineno, rval); - JS_SetOptions(cx, oldopts); - - return ok; -} - -#include -#include - -/* - * Returns a JS_malloc'd string (that the caller needs to JS_free) - * containing the directory (non-leaf) part of |from| prepended to |leaf|. - * If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf. - * Returns NULL to indicate an error. - */ -static char * -MakeAbsolutePathname(JSContext *cx, const char *from, const char *leaf) -{ - size_t dirlen; - char *dir; - const char *slash = NULL, *cp; - - cp = from; - while (*cp) { - if (*cp == '/' -#ifdef XP_WIN - || *cp == '\\' -#endif - ) { - slash = cp; - } - - ++cp; - } - - if (!slash) { - /* We were given a leaf or |from| was empty. */ - return JS_strdup(cx, leaf); - } - - /* Else, we were given a real pathname, return that + the leaf. */ - dirlen = slash - from + 1; - dir = JS_malloc(cx, dirlen + strlen(leaf) + 1); - if (!dir) - return NULL; - - strncpy(dir, from, dirlen); - strcpy(dir + dirlen, leaf); /* Note: we can't use strcat here. */ - - return dir; -} - -static JSBool -snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSString *str; - const char *filename; - char *pathname; - JSStackFrame *fp; - int fd, cc; - JSBool ok; - size_t len; - char *buf; - struct stat sb; - - str = JS_ValueToString(cx, argv[0]); - if (!str) - return JS_FALSE; - filename = JS_GetStringBytes(str); - - /* Get the currently executing script's name. */ - fp = JS_GetScriptedCaller(cx, NULL); - JS_ASSERT(fp && fp->script->filename); - pathname = MakeAbsolutePathname(cx, fp->script->filename, filename); - if (!pathname) - return JS_FALSE; - - fd = open(pathname, O_RDONLY); - ok = JS_TRUE; - len = 0; - buf = NULL; - if (fd < 0) { - JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno)); - ok = JS_FALSE; - } else if (fstat(fd, &sb) < 0) { - JS_ReportError(cx, "can't stat %s", pathname); - ok = JS_FALSE; - } else { - len = sb.st_size; - buf = JS_malloc(cx, len + 1); - if (!buf) { - ok = JS_FALSE; - } else if ((cc = read(fd, buf, len)) != len) { - JS_free(cx, buf); - JS_ReportError(cx, "can't read %s: %s", pathname, - (cc < 0) ? strerror(errno) : "short read"); - ok = JS_FALSE; - } - } - close(fd); - JS_free(cx, pathname); - if (!ok) - return ok; - buf[len] = '\0'; - str = JS_NewString(cx, buf, len); - if (!str) { - JS_free(cx, buf); - return JS_FALSE; - } - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -#endif /* NARCISSUS */ - -int -main(int argc, char **argv, char **envp) -{ - int stackDummy; - 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; - - argc--; - argv++; - - rt = JS_NewRuntime(64L * 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; - - 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; - -#ifdef NARCISSUS - { - jsval v; - static const char Object_prototype[] = "Object.prototype"; - - if (!JS_DefineFunction(cx, glob, "snarf", snarf, 1, 0)) - return 1; - if (!JS_DefineFunction(cx, glob, "evaluate", Evaluate, 3, 0)) - return 1; - - if (!JS_EvaluateScript(cx, glob, - Object_prototype, sizeof Object_prototype - 1, - NULL, 0, &v)) { - return 1; - } - if (!JS_DefineFunction(cx, JSVAL_TO_OBJECT(v), "__defineProperty__", - defineProperty, 5, 0)) { - return 1; - } - } -#endif - - result = ProcessArgs(cx, glob, argv, argc); - -#ifdef JSDEBUGGER - if (_jsdc) - JSD_DebuggerOff(_jsdc); -#endif /* JSDEBUGGER */ - - JS_DestroyContext(cx); - JS_DestroyRuntime(rt); - JS_ShutDown(); - return result; -} diff --git a/src/dom/js/js.msg b/src/dom/js/js.msg deleted file mode 100644 index 5df1ead9e..000000000 --- a/src/dom/js/js.msg +++ /dev/null @@ -1,290 +0,0 @@ -/* -*- 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(, , , , - * ) - * - * where ; - * is a legal C identifer that will be used in the - * JS engine source. - * - * is an unique integral value identifying this error. - * - * is an integer literal specifying the total number of - * replaceable arguments in the following format string. - * - * 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. - * - * 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 free - * index placeholders in the middle of the list. - */ - -MSG_DEF(JSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "") -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_NOT_SCRIPTED_FUNCTION, 11, 1, JSEXN_TYPEERR, "{0} is not a scripted function") -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_TOO_MANY_LOCAL_ROOTS, 18, 0, JSEXN_ERR, "out of local root space") -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_SYNTAXERR, "{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") -MSG_DEF(JSMSG_BAD_XML_MARKUP, 170, 0, JSEXN_SYNTAXERR, "invalid XML markup") -MSG_DEF(JSMSG_BAD_XML_CHARACTER, 171, 0, JSEXN_SYNTAXERR, "illegal XML character") -MSG_DEF(JSMSG_BAD_DEFAULT_XML_NAMESPACE,172,0,JSEXN_SYNTAXERR, "invalid default XML namespace") -MSG_DEF(JSMSG_BAD_XML_NAME_SYNTAX, 173, 0, JSEXN_SYNTAXERR, "invalid XML name") -MSG_DEF(JSMSG_BRACKET_AFTER_ATTR_EXPR,174, 0, JSEXN_SYNTAXERR, "missing ] after attribute expression") -MSG_DEF(JSMSG_NAME_AFTER_DBLDOT, 175, 0, JSEXN_SYNTAXERR, "missing name after .. operator") -MSG_DEF(JSMSG_CURLY_IN_XML_EXPR, 176, 0, JSEXN_SYNTAXERR, "missing } in XML expression") -MSG_DEF(JSMSG_BAD_XML_NAMESPACE, 177, 1, JSEXN_TYPEERR, "invalid XML namespace {0}") -MSG_DEF(JSMSG_BAD_XML_ATTR_NAME, 178, 1, JSEXN_TYPEERR, "invalid XML attribute name {0}") -MSG_DEF(JSMSG_BAD_XML_NAME, 179, 1, JSEXN_TYPEERR, "invalid XML name {0}") -MSG_DEF(JSMSG_BAD_XML_CONVERSION, 180, 1, JSEXN_TYPEERR, "can't convert {0} to XML") -MSG_DEF(JSMSG_BAD_XMLLIST_CONVERSION, 181, 1, JSEXN_TYPEERR, "can't convert {0} to XMLList") -MSG_DEF(JSMSG_IS_NOT_XML_OBJECT, 182, 1, JSEXN_TYPEERR, "{0} is not an XML object") -MSG_DEF(JSMSG_NO_ASSIGN_IN_XML_ATTR, 183, 0, JSEXN_SYNTAXERR, "missing = in XML attribute") -MSG_DEF(JSMSG_BAD_XML_ATTR_VALUE, 184, 0, JSEXN_SYNTAXERR, "invalid XML attribute value") -MSG_DEF(JSMSG_XML_TAG_NAME_MISMATCH, 185, 0, JSEXN_SYNTAXERR, "XML tag name mismatch") -MSG_DEF(JSMSG_BAD_XML_TAG_SYNTAX, 186, 0, JSEXN_SYNTAXERR, "invalid XML tag syntax") -MSG_DEF(JSMSG_BAD_XML_LIST_SYNTAX, 187, 0, JSEXN_SYNTAXERR, "invalid XML list syntax") -MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") -MSG_DEF(JSMSG_CANT_SET_XML_ATTRS, 189, 0, JSEXN_INTERNALERR, "can't set XML property attributes") -MSG_DEF(JSMSG_END_OF_XML_SOURCE, 190, 0, JSEXN_SYNTAXERR, "unexpected end of XML source") -MSG_DEF(JSMSG_END_OF_XML_ENTITY, 191, 0, JSEXN_SYNTAXERR, "unexpected end of XML entity") -MSG_DEF(JSMSG_BAD_XML_QNAME, 192, 0, JSEXN_SYNTAXERR, "invalid XML qualified name") -MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop") -MSG_DEF(JSMSG_BAD_XMLLIST_PUT, 194, 1, JSEXN_TYPEERR, "can't set property {0} in XMLList") -MSG_DEF(JSMSG_UNKNOWN_XML_ENTITY, 195, 1, JSEXN_TYPEERR, "unknown XML entity {0}") -MSG_DEF(JSMSG_BAD_XML_NCR, 196, 1, JSEXN_TYPEERR, "malformed XML character {0}") -MSG_DEF(JSMSG_UNDEFINED_XML_NAME, 197, 1, JSEXN_REFERENCEERR, "reference to undefined XML name {0}") -MSG_DEF(JSMSG_DUPLICATE_XML_ATTR, 198, 1, JSEXN_TYPEERR, "duplicate XML attribute {0}") -MSG_DEF(JSMSG_TOO_MANY_FUN_VARS, 199, 0, JSEXN_SYNTAXERR, "too many local variables") -MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 200, 0, JSEXN_INTERNALERR, "array initialiser too large") -MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX, 201, 0, JSEXN_INTERNALERR, "regular expression too complex") -MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 202, 1, JSEXN_TYPEERR, "wrong construtor called for {0}") -MSG_DEF(JSMSG_SELF_MODIFYING_SCRIPT, 203, 0, JSEXN_TYPEERR, "self-modifying script detected") -MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 204, 0, JSEXN_INTERNALERR, "buffer too small") -MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 205, 1, JSEXN_TYPEERR, "bad surrogate character {0}") -MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 206, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") -MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 207, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}") -MSG_DEF(JSMSG_USER_DEFINED_ERROR, 208, 0, JSEXN_ERR, "JS_ReportError was called") diff --git a/src/dom/js/jsapi.c b/src/dom/js/jsapi.c deleted file mode 100644 index 344fc2469..000000000 --- a/src/dom/js/jsapi.c +++ /dev/null @@ -1,4847 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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 -#include -#include -#include -#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 - -#if JS_HAS_XML_SUPPORT -#include "jsxml.h" -#endif - -#ifdef HAVE_VA_LIST_AS_ARRAY -#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(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': - obj = js_ValueToFunctionObject(cx, sp, 0); - if (!obj) - return JS_FALSE; - *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj); - 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; - 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: - *vp = v; - obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK); - ok = (obj != NULL); - 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, 0); - 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)) { - type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */ - obj = JSVAL_TO_OBJECT(v); - if (obj) { - ops = obj->map->ops; -#if JS_HAS_XML_SUPPORT - if (ops == &js_XMLObjectOps.base) { - type = JSTYPE_XML; - } else -#endif - { - /* - * ECMA 262, 11.4.3 says that any native object that implements - * [[Call]] should be of type "function". Note that RegExp and - * Script are both of type "function" for compatibility with - * older SpiderMonkeys. - */ - clasp = OBJ_GET_CLASS(cx, obj); - if ((ops == &js_ObjectOps) - ? (clasp->call - ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass) - : clasp == &js_FunctionClass) - : ops->call != NULL) { - type = JSTYPE_FUNCTION; - } else { -#ifdef NARCISSUS - if (!OBJ_GET_PROPERTY(cx, obj, - ATOM_TO_JSID(cx->runtime->atomState - .callAtom), - &v)) { - JS_ClearPendingException(cx); - } else if (JSVAL_IS_FUNCTION(cx, v)) { - type = JSTYPE_FUNCTION; - } -#endif - } - } - } - } 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_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; - /* this is asymmetric with JS_ShutDown: */ - if (!js_SetupLocks(8, 16)) - goto bad; - 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_FreeRuntimeScriptState(rt); - 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_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 & JSVERSION_MASK; -} - -JS_PUBLIC_API(JSVersion) -JS_SetVersion(JSContext *cx, JSVersion version) -{ - JSVersion oldVersion; - - JS_ASSERT(version != JSVERSION_UNKNOWN); - JS_ASSERT((version & ~JSVERSION_MASK) == 0); - - oldVersion = cx->version & JSVERSION_MASK; - if (version == oldVersion) - return oldVersion; - - cx->version = (cx->version & ~JSVERSION_MASK) | version; - js_OnVersionChange(cx); - 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_1_6, "1.6"}, - {JSVERSION_DEFAULT, js_default_str}, - {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; -} - -#define SYNC_OPTIONS_TO_VERSION(cx) \ - JS_BEGIN_MACRO \ - if ((cx)->options & JSOPTION_XML) \ - (cx)->version |= JSVERSION_HAS_XML; \ - else \ - (cx)->version &= ~JSVERSION_HAS_XML; \ - JS_END_MACRO - -JS_PUBLIC_API(uint32) -JS_SetOptions(JSContext *cx, uint32 options) -{ - uint32 oldopts = cx->options; - cx->options = options; - SYNC_OPTIONS_TO_VERSION(cx); - return oldopts; -} - -JS_PUBLIC_API(uint32) -JS_ToggleOptions(JSContext *cx, uint32 options) -{ - uint32 oldopts = cx->options; - cx->options ^= options; - SYNC_OPTIONS_TO_VERSION(cx); - return oldopts; -} - -JS_PUBLIC_API(const char *) -JS_GetImplementationVersion(void) -{ - return "JavaScript-C 1.6 2006-11-19"; -} - - -JS_PUBLIC_API(JSObject *) -JS_GetGlobalObject(JSContext *cx) -{ - return cx->globalObject; -} - -JS_PUBLIC_API(void) -JS_SetGlobalObject(JSContext *cx, JSObject *obj) -{ - cx->globalObject = obj; -#if JS_HAS_XML_SUPPORT - cx->xmlSettingFlags = 0; -#endif -} - -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) - JS_SetGlobalObject(cx, 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 = ATOM_TO_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 = ATOM_TO_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, ATOM_TO_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_XML_SUPPORT - js_InitXMLClasses(cx, obj) && -#endif -#if JS_HAS_FILE_OBJECT - js_InitFileClass(cx, obj) && -#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 -#if JS_HAS_XML_SUPPORT - {js_InitXMLClass, ATOM_OFFSET(XML)}, - {js_InitNamespaceClass, ATOM_OFFSET(Namespace)}, - {js_InitQNameClass, ATOM_OFFSET(QName)}, -#endif -#if JS_HAS_FILE_OBJECT - {js_InitFileClass, ATOM_OFFSET(File)}, -#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 - -#if JS_HAS_XML_SUPPORT - {js_InitAnyNameClass, LAZILY_PINNED_ATOM(AnyName)}, - {js_InitAttributeNameClass, LAZILY_PINNED_ATOM(AttributeName)}, - {js_InitXMLClass, LAZILY_PINNED_ATOM(XMLList)}, - {js_InitXMLClass, LAZILY_PINNED_ATOM(isXMLName)}, -#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 - /* Check whether 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, ATOM_TO_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 -AlreadyHasOwnProperty(JSObject *obj, JSAtom *atom) -{ - JS_ASSERT(OBJ_IS_NATIVE(obj)); - return SCOPE_GET_PROPERTY(OBJ_SCOPE(obj), ATOM_TO_JSID(atom)) != NULL; -} - -JS_PUBLIC_API(JSBool) -JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) -{ - JSRuntime *rt; - JSAtom *atom; - uintN i; - - CHECK_REQUEST(cx); - rt = cx->runtime; - -#if JS_HAS_UNDEFINED - /* Check whether we need to bind 'undefined' and define it if so. */ - atom = rt->atomState.typeAtoms[JSTYPE_VOID]; - if (!AlreadyHasOwnProperty(obj, atom) && - !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_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 (!AlreadyHasOwnProperty(obj, atom) && - !standard_class_atoms[i].init(cx, obj)) { - return JS_FALSE; - } - } - - return JS_TRUE; -} - -static JSIdArray * -AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip) -{ - jsint i, length; - - i = *ip; - length = ida->length; - if (i >= length) { - ida = js_SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8)); - if (!ida) - return NULL; - JS_ASSERT(i < ida->length); - } - ida->vector[i] = ATOM_TO_JSID(atom); - *ip = i + 1; - return ida; -} - -static JSIdArray * -EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida, - jsint *ip, JSBool *foundp) -{ - *foundp = AlreadyHasOwnProperty(obj, atom); - if (*foundp) - ida = AddAtomToArray(cx, atom, ida, ip); - return ida; -} - -JS_PUBLIC_API(JSIdArray *) -JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, - JSIdArray *ida) -{ - JSRuntime *rt; - jsint i, j, k; - JSAtom *atom; - JSBool found; - JSObjectOp init; - - CHECK_REQUEST(cx); - rt = cx->runtime; - if (ida) { - i = ida->length; - } else { - ida = js_NewIdArray(cx, 8); - if (!ida) - return NULL; - i = 0; - } - -#if JS_HAS_UNDEFINED - /* Check whether 'undefined' has been resolved and enumerate it if so. */ - atom = rt->atomState.typeAtoms[JSTYPE_VOID]; - ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); - if (!ida) - return NULL; -#endif - - /* Enumerate only classes that *have* been resolved. */ - for (j = 0; standard_class_atoms[j].init; j++) { - atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset); - ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); - if (!ida) - return NULL; - - if (found) { - init = standard_class_atoms[j].init; - - for (k = 0; standard_class_names[k].init; k++) { - if (standard_class_names[k].init == init) { - atom = StdNameToAtom(cx, &standard_class_names[k]); - ida = AddAtomToArray(cx, atom, ida, &i); - if (!ida) - return NULL; - } - } - - if (init == js_InitObjectClass) { - for (k = 0; object_prototype_names[k].init; k++) { - atom = StdNameToAtom(cx, &object_prototype_names[k]); - ida = AddAtomToArray(cx, atom, ida, &i); - if (!ida) - return NULL; - } - } - } - } - - /* Trim to exact length via js_SetIdArrayLength. */ - return js_SetIdArrayLength(cx, ida, i); -} - -#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, 0); -} - -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; - cx->lastInternalResult = JSVAL_NULL; -} - -JS_PUBLIC_API(JSBool) -JS_EnterLocalRootScope(JSContext *cx) -{ - CHECK_REQUEST(cx); - return js_EnterLocalRootScope(cx); -} - -JS_PUBLIC_API(void) -JS_LeaveLocalRootScope(JSContext *cx) -{ - CHECK_REQUEST(cx); - js_LeaveLocalRootScope(cx); -} - -JS_PUBLIC_API(void) -JS_ForgetLocalRoot(JSContext *cx, void *thing) -{ - CHECK_REQUEST(cx); - js_ForgetLocalRoot(cx, (jsval) thing); -} - -#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) -{ -#ifdef WAY_TOO_MUCH_GC - JS_GC(cx); -#else - JSRuntime *rt; - uint32 bytes, lastBytes; - - rt = cx->runtime; - bytes = rt->gcBytes; - lastBytes = rt->gcLastBytes; - if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) || - rt->gcMallocBytes > rt->gcMaxMallocBytes) { - /* - * 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); - } -#endif -} - -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(void) -JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value) -{ - switch (key) { - case JSGC_MAX_BYTES: - rt->gcMaxBytes = value; - break; - case JSGC_MAX_MALLOC_BYTES: - rt->gcMaxMallocBytes = value; - break; - } -} - -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_NewGCThing(cx, (uintN) type, sizeof(JSString)); - 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; -} - -JS_PUBLIC_API(void) -JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr) -{ -#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 = ATOM_TO_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 - js_TryValueOf(cx, obj, type, vp); - return JS_TRUE; -} - -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; - JSTempValueRooter tvr; - jsval cval, rval; - JSBool named; - JSFunction *fun; - - 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; - - /* After this point, control must exit via label bad or out. */ - JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr); - - if (!constructor) { - /* Lacking a constructor, name the prototype (e.g., Math). */ - named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_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; - - /* - * Optionally construct the prototype object, before the class has - * been fully initialized. Allow the ctor to replace proto with a - * different object, as is done for operator new -- and as at least - * XML support requires. - */ - ctor = fun->object; - if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) { - cval = OBJECT_TO_JSVAL(ctor); - if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval)) - goto bad; - if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto) - proto = JSVAL_TO_OBJECT(rval); - } - - /* Connect constructor and prototype by named properties. */ - 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; - } - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - return proto; - -bad: - if (named) - (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval); - proto = NULL; - goto out; -} - -#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(JSBool) -JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) -{ - return js_HasInstance(cx, obj, v, bp); -} - -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, - ATOM_TO_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) -{ - JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0); - *idp = OBJECT_TO_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_JSID(JS_PTR_TO_INT32(name)); - atom = NULL; - attrs &= ~JSPROP_INDEX; - } else { - atom = js_Atomize(cx, name, strlen(name), 0); - if (!atom) - return JS_FALSE; - id = ATOM_TO_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, ATOM_TO_JSID(atom), value, - getter, setter, attrs, flags, tinyid, - NULL); - } - return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_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, ATOM_TO_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, ATOM_TO_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, ATOM_TO_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, - JSPropertyOp *getterp, JSPropertyOp *setterp) -{ - JSObject *obj2; - JSProperty *prop; - JSBool ok; - - if (!atom) - return JS_FALSE; - if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop)) - return JS_FALSE; - - if (!prop || obj != obj2) { - *attrsp = 0; - *foundp = JS_FALSE; - if (getterp) - *getterp = NULL; - if (setterp) - *setterp = NULL; - if (prop) - OBJ_DROP_PROPERTY(cx, obj2, prop); - return JS_TRUE; - } - - *foundp = JS_TRUE; - ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp); - if (ok && OBJ_IS_NATIVE(obj)) { - JSScopeProperty *sprop = (JSScopeProperty *) prop; - - if (getterp) - *getterp = sprop->getter; - if (setterp) - *setterp = sprop->setter; - } - 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, ATOM_TO_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, ATOM_TO_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, NULL, NULL); -} - -JS_PUBLIC_API(JSBool) -JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, - const char *name, - uintN *attrsp, JSBool *foundp, - JSPropertyOp *getterp, - JSPropertyOp *setterp) -{ - CHECK_REQUEST(cx); - return GetPropertyAttributes(cx, obj, - js_Atomize(cx, name, strlen(name), 0), - attrsp, foundp, getterp, setterp); -} - -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_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp) -{ - JSBool ok; - JSObject *obj2; - JSProperty *prop; - - CHECK_REQUEST(cx); - ok = LookupProperty(cx, obj, name, &obj2, &prop); - if (ok) { - *foundp = (prop != NULL); - if (prop) - OBJ_DROP_PROPERTY(cx, obj2, prop); - } - return ok; -} - -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_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, - uintN flags, jsval *vp) -{ - JSAtom *atom; - JSBool ok; - JSObject *obj2; - JSProperty *prop; - - CHECK_REQUEST(cx); - atom = js_Atomize(cx, name, strlen(name), 0); - if (!atom) - return JS_FALSE; - ok = OBJ_IS_NATIVE(obj) - ? js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom), flags, - &obj2, &prop) - : OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &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, ATOM_TO_JSID(atom), vp); -} - -JS_PUBLIC_API(JSBool) -JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, - jsval *vp) -{ - JSAtom *atom; - jsid id; - - CHECK_REQUEST(cx); - atom = js_Atomize(cx, name, strlen(name), 0); - if (!atom) - return JS_FALSE; - id = ATOM_TO_JSID(atom); - -#if JS_HAS_XML_SUPPORT - if (OBJECT_IS_XML(cx, obj)) { - JSXMLObjectOps *ops; - - ops = (JSXMLObjectOps *) obj->map->ops; - obj = ops->getMethod(cx, obj, id, vp); - if (!obj) - return JS_FALSE; - } else -#endif - { - if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) - return JS_FALSE; - } - - *objp = obj; - return JS_TRUE; -} - -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, ATOM_TO_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, ATOM_TO_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, NULL, NULL); -} - -JS_PUBLIC_API(JSBool) -JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, - const jschar *name, size_t namelen, - uintN *attrsp, JSBool *foundp, - JSPropertyOp *getterp, - JSPropertyOp *setterp) -{ - CHECK_REQUEST(cx); - return GetPropertyAttributes(cx, obj, - js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0), - attrsp, foundp, getterp, setterp); -} - -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_HasUCProperty(JSContext *cx, JSObject *obj, - const jschar *name, size_t namelen, - JSBool *vp) -{ - JSBool ok; - JSObject *obj2; - JSProperty *prop; - - CHECK_REQUEST(cx); - ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop); - if (ok) { - *vp = (prop != NULL); - if (prop) - OBJ_DROP_PROPERTY(cx, obj2, prop); - } - return ok; -} - -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, ATOM_TO_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, ATOM_TO_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, ATOM_TO_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_JSID(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_JSID(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_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp) -{ - JSBool ok; - JSObject *obj2; - JSProperty *prop; - - CHECK_REQUEST(cx); - ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop); - if (ok) { - *foundp = (prop != NULL); - if (prop) - OBJ_DROP_PROPERTY(cx, obj2, 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_JSID(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_JSID(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_JSID(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_JSID(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 (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id)) - goto error; - - /* No more jsid's to enumerate ? */ - if (iter_state == JSVAL_NULL) - break; - - if (i == ida->length) { - ida = js_SetIdArrayLength(cx, ida, ida->length * 2); - if (!ida) - goto error; - vector = &ida->vector[0]; - } - vector[i++] = id; - } - return js_SetIdArrayLength(cx, ida, i); - -error: - if (iter_state != JSVAL_NULL) - OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0); - if (ida) - JS_DestroyIdArray(cx, ida); - return NULL; -} - -/* - * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's - * prop_iterator_class somehow... - * + preserve the OBJ_ENUMERATE API while optimizing the native object case - * + native case here uses a JSScopeProperty *, but that iterates in reverse! - * + so we make non-native match, by reverse-iterating after JS_Enumerating - */ -#define JSSLOT_ITER_INDEX (JSSLOT_PRIVATE + 1) - -#if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS -# error "JSSLOT_ITER_INDEX botch!" -#endif - -static void -prop_iter_finalize(JSContext *cx, JSObject *obj) -{ - jsval v; - jsint i; - JSIdArray *ida; - - v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX); - if (JSVAL_IS_VOID(v)) - return; - - i = JSVAL_TO_INT(v); - if (i >= 0) { - /* Non-native case: destroy the ida enumerated when obj was created. */ - ida = (JSIdArray *) JS_GetPrivate(cx, obj); - if (ida) - JS_DestroyIdArray(cx, ida); - } -} - -static uint32 -prop_iter_mark(JSContext *cx, JSObject *obj, void *arg) -{ - jsval v; - jsint i, n; - JSScopeProperty *sprop; - JSIdArray *ida; - jsid id; - - v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - JS_ASSERT(!JSVAL_IS_VOID(v)); - - i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX)); - if (i < 0) { - /* Native case: just mark the next property to visit. */ - sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v); - if (sprop) - MARK_SCOPE_PROPERTY(sprop); - } else { - /* Non-native case: mark each id in the JSIdArray private. */ - ida = (JSIdArray *) JSVAL_TO_PRIVATE(v); - for (i = 0, n = ida->length; i < n; i++) { - id = ida->vector[i]; - if (JSID_IS_ATOM(id)) - GC_MARK_ATOM(cx, JSID_TO_ATOM(id), arg); - else if (JSID_IS_OBJECT(id)) - GC_MARK(cx, JSID_TO_OBJECT(id), "id", arg); - } - } - return 0; -} - -static JSClass prop_iter_class = { - "PropertyIterator", - JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize, - NULL, NULL, NULL, NULL, - NULL, NULL, prop_iter_mark, NULL -}; - -JS_PUBLIC_API(JSObject *) -JS_NewPropertyIterator(JSContext *cx, JSObject *obj) -{ - JSObject *iterobj; - JSScope *scope; - void *pdata; - jsint index; - JSIdArray *ida; - - CHECK_REQUEST(cx); - iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj); - if (!iterobj) - return NULL; - - if (OBJ_IS_NATIVE(obj)) { - /* Native case: start with the last property in obj's own scope. */ - scope = OBJ_SCOPE(obj); - pdata = (scope->object == obj) ? scope->lastProp : NULL; - index = -1; - } else { - JSTempValueRooter tvr; - - /* - * Non-native case: enumerate a JSIdArray and keep it via private. - * - * Note: we have to make sure that we root obj around the call to - * JS_Enumerate to protect against multiple allocations under it. - */ - JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr); - ida = JS_Enumerate(cx, obj); - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ida) - goto bad; - pdata = ida; - index = ida->length; - } - - /* iterobj can not escape to other threads here. */ - iterobj->slots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(pdata); - iterobj->slots[JSSLOT_ITER_INDEX] = INT_TO_JSVAL(index); - return iterobj; - -bad: - cx->newborn[GCX_OBJECT] = NULL; - return NULL; -} - -JS_PUBLIC_API(JSBool) -JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) -{ - jsint i; - JSObject *obj; - JSScope *scope; - JSScopeProperty *sprop; - JSIdArray *ida; - - CHECK_REQUEST(cx); - i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX)); - if (i < 0) { - /* Native case: private data is a property tree node pointer. */ - obj = OBJ_GET_PARENT(cx, iterobj); - JS_ASSERT(OBJ_IS_NATIVE(obj)); - scope = OBJ_SCOPE(obj); - JS_ASSERT(scope->object == obj); - sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj); - - /* - * If the next property mapped by scope in the property tree ancestor - * line is not enumerable, or it's an alias, or one or more properties - * were deleted from the "middle" of the scope-mapped ancestor line - * and the next property was among those deleted, skip it and keep on - * trying to find an enumerable property that is still in scope. - */ - while (sprop && - (!(sprop->attrs & JSPROP_ENUMERATE) || - (sprop->flags & SPROP_IS_ALIAS) || - (SCOPE_HAD_MIDDLE_DELETE(scope) && - !SCOPE_HAS_PROPERTY(scope, sprop)))) { - sprop = sprop->parent; - } - - if (!sprop) { - *idp = JSVAL_VOID; - } else { - if (!JS_SetPrivate(cx, iterobj, sprop->parent)) - return JS_FALSE; - *idp = sprop->id; - } - } else { - /* Non-native case: use the ida enumerated when iterobj was created. */ - ida = (JSIdArray *) JS_GetPrivate(cx, iterobj); - JS_ASSERT(i <= ida->length); - if (i == 0) { - *idp = JSVAL_VOID; - } else { - *idp = ida->vector[--i]; - OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i)); - } - } - return JS_TRUE; -} - -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; -} - -static JSBool -ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp, - uint32 index, uint32 limit) -{ - /* Check the computed, possibly per-instance, upper bound. */ - if (clasp->reserveSlots) - JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj)); - if (index >= limit) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_RESERVED_SLOT_RANGE); - return JS_FALSE; - } - return JS_TRUE; -} - -JS_PUBLIC_API(JSBool) -JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) -{ - JSClass *clasp; - uint32 limit, slot; - - CHECK_REQUEST(cx); - clasp = OBJ_GET_CLASS(cx, obj); - limit = JSCLASS_RESERVED_SLOTS(clasp); - if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit)) - 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 limit, slot; - - CHECK_REQUEST(cx); - clasp = OBJ_GET_CLASS(cx, obj); - limit = JSCLASS_RESERVED_SLOTS(clasp); - if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit)) - return JS_FALSE; - slot = JSSLOT_START(clasp) + index; - return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v); -} - -#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(JSRuntime *rt, JSObjectPrincipalsFinder fop) -{ - JSObjectPrincipalsFinder oldfop; - - oldfop = rt->findObjectPrincipals; - rt->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(uint16) -JS_GetFunctionArity(JSFunction *fun) -{ - return fun->nargs; -} - -JS_PUBLIC_API(JSBool) -JS_ObjectIsFunction(JSContext *cx, JSObject *obj) -{ - return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass; -} - -JS_STATIC_DLL_CALLBACK(JSBool) -js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) -{ - jsval fsv; - JSFunctionSpec *fs; - JSObject *tmp; - - if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv)) - return JS_FALSE; - fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv); - - /* - * We know that argv[0] is valid because JS_DefineFunctions, which is our - * only (indirect) referrer, defined us as requiring at least one argument - * (notice how it passes fs->nargs + 1 as the next-to-last argument to - * JS_DefineFunction). - */ - if (JSVAL_IS_PRIMITIVE(argv[0])) { - /* - * Make sure that this is an object or null, as required by the generic - * functions. - */ - if (!js_ValueToObject(cx, argv[0], &tmp)) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(tmp); - } - - /* - * Copy all actual (argc) and required but missing (fs->nargs + 1 - argc) - * args down over our |this| parameter, argv[-1], which is almost always - * the class constructor object, e.g. Array. Then call the corresponding - * prototype native method with our first argument passed as |this|. - */ - memmove(argv - 1, argv, JS_MAX(fs->nargs + 1U, argc) * sizeof(jsval)); - - /* - * Follow Function.prototype.apply and .call by using the global object as - * the 'this' param if no args. - */ - JS_ASSERT(cx->fp->argv == argv); - if (!js_ComputeThis(cx, JSVAL_TO_OBJECT(argv[-1]), cx->fp)) - return JS_FALSE; - - /* - * Protect against argc - 1 underflowing below. By calling js_ComputeThis, - * we made it as if the static was called with one parameter. - */ - if (argc == 0) - argc = 1; - - return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval); -} - -JS_PUBLIC_API(JSBool) -JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) -{ - uintN flags; - JSObject *ctor; - JSFunction *fun; - - CHECK_REQUEST(cx); - ctor = NULL; - for (; fs->name; fs++) { - flags = fs->flags; - - /* - * Define a generic arity N+1 static method for the arity N prototype - * method if flags contains JSFUN_GENERIC_NATIVE. - */ - if (flags & JSFUN_GENERIC_NATIVE) { - if (!ctor) { - ctor = JS_GetConstructor(cx, obj); - if (!ctor) - return JS_FALSE; - } - - flags &= ~JSFUN_GENERIC_NATIVE; - fun = JS_DefineFunction(cx, ctor, fs->name, - js_generic_native_method_dispatcher, - fs->nargs + 1, flags); - if (!fun) - return JS_FALSE; - fun->extra = fs->extra; - - /* - * As jsapi.h notes, fs must point to storage that lives as long - * as fun->object lives. - */ - if (!JS_SetReservedSlot(cx, fun->object, 0, PRIVATE_TO_JSVAL(fs))) - return JS_FALSE; - } - - fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, 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); -} - -JS_PUBLIC_API(JSFunction *) -JS_DefineUCFunction(JSContext *cx, JSObject *obj, - const jschar *name, size_t namelen, JSNative call, - uintN nargs, uintN attrs) -{ - JSAtom *atom; - - atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 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(¬ePool, "note", 1024, sizeof(jssrcnote)); - if (!js_InitCodeGenerator(cx, &cg, &codePool, ¬ePool, - 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(¬ePool); - 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); -} - -#if JS_HAS_EXCEPTIONS -# define LAST_FRAME_EXCEPTION_CHECK(cx,result) \ - JS_BEGIN_MACRO \ - if (!(result)) \ - js_ReportUncaughtException(cx); \ - JS_END_MACRO -#else -# define LAST_FRAME_EXCEPTION_CHECK(cx,result) /* nothing */ -#endif - -#define LAST_FRAME_CHECKS(cx,result) \ - JS_BEGIN_MACRO \ - if (!(cx)->fp) { \ - (cx)->lastInternalResult = JSVAL_NULL; \ - LAST_FRAME_EXCEPTION_CHECK(cx, result); \ - } \ - JS_END_MACRO - -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); - LAST_FRAME_CHECKS(cx, script); - 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) && - (ts->flags & TSF_UNEXPECTED_EOF)) { - /* - * 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 = JS_FALSE; - } - - 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); - LAST_FRAME_CHECKS(cx, script); - 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); - LAST_FRAME_CHECKS(cx, script); - return script; -} - -JS_PUBLIC_API(JSObject *) -JS_NewScriptObject(JSContext *cx, JSScript *script) -{ - JSObject *obj; - - obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); - 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_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom), - js_GetArgument, js_SetArgument, - SPROP_INVALID_SLOT, - 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, ATOM_TO_JSID(funAtom), - OBJECT_TO_JSVAL(fun->object), - NULL, NULL, JSPROP_ENUMERATE, NULL)) { - return NULL; - } - } -out: - if (ts) - js_CloseTokenStream(cx, ts); - JS_ARENA_RELEASE(&cx->tempPool, mark); - LAST_FRAME_CHECKS(cx, fun); - 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) -{ - JSBool ok; - - CHECK_REQUEST(cx); - ok = js_Execute(cx, obj, script, NULL, 0, rval); - LAST_FRAME_CHECKS(cx, ok); - return ok; -} - -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 nbytes, - const char *filename, uintN lineno, - jsval *rval) -{ - size_t length = nbytes; - 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 nbytes, - const char *filename, uintN lineno, - jsval *rval) -{ - size_t length = nbytes; - 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) -{ - uint32 options; - JSScript *script; - JSBool ok; - - CHECK_REQUEST(cx); - options = cx->options; - cx->options = options | JSOPTION_COMPILE_N_GO; - script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, - filename, lineno); - cx->options = options; - if (!script) - return JS_FALSE; - ok = js_Execute(cx, obj, script, NULL, 0, rval); - LAST_FRAME_CHECKS(cx, ok); - JS_DestroyScript(cx, script); - return ok; -} - -JS_PUBLIC_API(JSBool) -JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, - jsval *argv, jsval *rval) -{ - JSBool ok; - - CHECK_REQUEST(cx); - ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv, - rval); - LAST_FRAME_CHECKS(cx, ok); - return ok; -} - -JS_PUBLIC_API(JSBool) -JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, - jsval *argv, jsval *rval) -{ - JSBool ok; - jsval fval; - - CHECK_REQUEST(cx); -#if JS_HAS_XML_SUPPORT - if (OBJECT_IS_XML(cx, obj)) { - JSXMLObjectOps *ops; - JSAtom *atom; - - ops = (JSXMLObjectOps *) obj->map->ops; - atom = js_Atomize(cx, name, strlen(name), 0); - if (!atom) - return JS_FALSE; - obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval); - if (!obj) - return JS_FALSE; - } else -#endif - if (!JS_GetProperty(cx, obj, name, &fval)) - return JS_FALSE; - ok = js_InternalCall(cx, obj, fval, argc, argv, rval); - LAST_FRAME_CHECKS(cx, ok); - return ok; -} - -JS_PUBLIC_API(JSBool) -JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, - jsval *argv, jsval *rval) -{ - JSBool ok; - - CHECK_REQUEST(cx); - ok = js_InternalCall(cx, obj, fval, argc, argv, rval); - LAST_FRAME_CHECKS(cx, ok); - return ok; -} - -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; - size_t charsLength = length; - - CHECK_REQUEST(cx); - /* Make a Unicode vector from the 8-bit char codes in bytes. */ - chars = js_InflateString(cx, bytes, &charsLength); - if (!chars) - return NULL; - - /* Free chars (but not bytes, which caller frees on error) if we fail. */ - str = js_NewString(cx, chars, charsLength, 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(JSBool) -JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, - size_t *dstlenp) -{ - return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp); -} - -JS_PUBLIC_API(JSBool) -JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, - size_t *dstlenp) -{ - return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp); -} - -JS_PUBLIC_API(JSBool) -JS_StringsAreUTF8 () -{ -#ifdef JS_C_STRINGS_ARE_UTF8 - return JS_TRUE; -#else - return JS_FALSE; -#endif -} - -/************************************************************************/ - -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 -} - -JS_PUBLIC_API(JSBool) -JS_ReportPendingException(JSContext *cx) -{ -#if JS_HAS_EXCEPTIONS - JSBool save, ok; - - CHECK_REQUEST(cx); - - /* - * Set cx->creatingException to suppress the standard error-to-exception - * conversion done by all {js,JS}_Report* functions except for OOM. The - * cx->creatingException flag was added to suppress recursive divergence - * under js_ErrorToException, but it serves for our purposes here too. - */ - save = cx->creatingException; - cx->creatingException = JS_TRUE; - ok = js_ReportUncaughtException(cx); - cx->creatingException = save; - return ok; -#else - return JS_TRUE; -#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_ERROR_EXCEPTIONS - CHECK_REQUEST(cx); - return js_ErrorFromException(cx, v); -#else - return NULL; -#endif -} - -JS_PUBLIC_API(JSBool) -JS_ThrowReportedError(JSContext *cx, const char *message, - JSErrorReport *reportp) -{ - return js_ErrorToException(cx, message, reportp); -} - -#ifdef JS_THREADSAFE -JS_PUBLIC_API(jsword) -JS_GetContextThread(JSContext *cx) -{ - return cx->thread; -} - -JS_PUBLIC_API(jsword) -JS_SetContextThread(JSContext *cx) -{ - jsword old = cx->thread; - cx->thread = js_CurrentThreadId(); - return old; -} - -JS_PUBLIC_API(jsword) -JS_ClearContextThread(JSContext *cx) -{ - jsword old = cx->thread; - cx->thread = 0; - return old; -} -#endif - -/************************************************************************/ - -#if defined(XP_WIN) -#include -/* - * 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 deleted file mode 100644 index 9fe07ac60..000000000 --- a/src/dom/js/jsapi.h +++ /dev/null @@ -1,2027 +0,0 @@ -/* -*- 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 -#include -#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 */ - -/* - * Re-use JSFUN_LAMBDA, which applies only to scripted functions, for use in - * JSFunctionSpec arrays that specify generic native prototype methods, i.e., - * methods of a class prototype that are exposed as static methods taking an - * extra leading argument: the generic |this| parameter. - * - * If you set this flag in a JSFunctionSpec struct's flags initializer, then - * that struct must live at least as long as the native static method object - * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically - * JSFunctionSpec structs are allocated in static arrays. - */ -#define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA - -/* - * 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 */ -#define JSOPTION_COMPILE_N_GO JS_BIT(4) /* caller of JS_Compile*Script - promises to execute compiled - script once only; enables - compile-time scope chain - resolution of consts. */ -#define JSOPTION_ATLINE JS_BIT(5) /* //@line number ["filename"] - option supported for the - XUL preprocessor and kindred - beasts. */ -#define JSOPTION_XML JS_BIT(6) /* EMCAScript for XML support: - parse as a token, - not backward compatible with - the comment-hiding hack used - in HTML script tags. */ -#define JSOPTION_NATIVE_BRANCH_CALLBACK \ - JS_BIT(7) /* the branch callback set by - JS_SetBranchCallback may be - called with a null script - parameter, by native code - that loops intensively */ - -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); - -/* - * Enumerate any already-resolved standard class ids into ida, or into a new - * JSIdArray if ida is null. Return the augmented array on success, null on - * failure with ida (if it was non-null on entry) destroyed. - */ -extern JS_PUBLIC_API(JSIdArray *) -JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, - JSIdArray *ida); - -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. - * - * See the scoped local root API immediately below for a better way to manage - * newborns in cases where native hooks (functions, getters, setters, etc.) - * create many GC-things, potentially without connecting them to predefined - * local roots such as *rval or argv[i] in an active native function. Using - * JS_EnterLocalRootScope disables updating of the context's per-gc-thing-type - * newborn roots, until control flow unwinds and leaves the outermost nesting - * local root scope. - */ -extern JS_PUBLIC_API(void) -JS_ClearNewbornRoots(JSContext *cx); - -/* - * Scoped local root management allows native functions, getter/setters, etc. - * to avoid worrying about the newborn root pigeon-holes, overloading local - * roots allocated in argv and *rval, or ending up having to call JS_Add*Root - * and JS_RemoveRoot to manage global roots temporarily. - * - * Instead, calling JS_EnterLocalRootScope and JS_LeaveLocalRootScope around - * the body of the native hook causes the engine to allocate a local root for - * each newborn created in between the two API calls, using a local root stack - * associated with cx. For example: - * - * JSBool - * my_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) - * { - * JSBool ok; - * - * if (!JS_EnterLocalRootScope(cx)) - * return JS_FALSE; - * ok = my_GetPropertyBody(cx, obj, id, vp); - * JS_LeaveLocalRootScope(cx); - * return ok; - * } - * - * NB: JS_LeaveLocalRootScope must be called once for every prior successful - * call to JS_EnterLocalRootScope. If JS_EnterLocalRootScope fails, you must - * not make the matching JS_LeaveLocalRootScope call. - * - * In case a native hook allocates many objects or other GC-things, but the - * native protects some of those GC-things by storing them as property values - * in an object that is itself protected, the hook can call JS_ForgetLocalRoot - * to free the local root automatically pushed for the now-protected GC-thing. - * - * JS_ForgetLocalRoot works on any GC-thing allocated in the current local - * root scope, but it's more time-efficient when called on references to more - * recently created GC-things. Calling it successively on other than the most - * recently allocated GC-thing will tend to average the time inefficiency, and - * may risk O(n^2) growth rate, but in any event, you shouldn't allocate too - * many local roots if you can root as you go (build a tree of objects from - * the top down, forgetting each latest-allocated GC-thing immediately upon - * linking it to its parent). - */ -extern JS_PUBLIC_API(JSBool) -JS_EnterLocalRootScope(JSContext *cx); - -extern JS_PUBLIC_API(void) -JS_LeaveLocalRootScope(JSContext *cx); - -extern JS_PUBLIC_API(void) -JS_ForgetLocalRoot(JSContext *cx, void *thing); - -#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); - -typedef enum JSGCParamKey { - JSGC_MAX_BYTES = 0, /* maximum nominal heap before last ditch GC */ - JSGC_MAX_MALLOC_BYTES = 1 /* # of JS_malloc bytes before last ditch GC */ -} JSGCParamKey; - -extern JS_PUBLIC_API(void) -JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value); - -/* - * Add a finalizer for external strings 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; - JSReserveSlotsOp reserveSlots; -}; - -struct JSExtendedClass { - JSClass base; - JSEqualityOp equality; - JSObjectOp outerObject; - JSObjectOp innerObject; - jsword reserved0; - jsword reserved1; - jsword reserved2; - jsword reserved3; - jsword reserved4; -}; - -#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 */ -#define JSCLASS_CONSTRUCT_PROTOTYPE (1<<6) /* call constructor on class - prototype */ -#define JSCLASS_DOCUMENT_OBSERVER (1<<7) /* DOM document observer */ - -/* - * 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) - -#define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \ - JSCLASS_RESERVED_SLOTS_WIDTH) - -/* True if JSClass is really a JSExtendedClass. */ -#define JSCLASS_IS_EXTENDED (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0)) - -/* Initializer for unused members of statically initialized JSClass structs. */ -#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0 -#define JSCLASS_NO_RESERVED_MEMBERS 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; -}; - -struct JSXMLObjectOps { - JSObjectOps base; - JSGetMethodOp getMethod; - JSSetMethodOp setMethod; - JSEnumerateValuesOp enumerateValues; - JSEqualityOp equality; - JSConcatenateOp concatenate; -}; - -/* - * 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); - -/* - * The magic XML namespace id is int-tagged, but not a valid integer jsval. - * Global object classes in embeddings that enable JS_HAS_XML_SUPPORT (E4X) - * should handle this id specially before converting id via JSVAL_TO_INT. - */ -#define JS_DEFAULT_XML_NAMESPACE_ID ((jsid) JSVAL_VOID) - -/* - * JSNewResolveOp flag bits. - */ -#define JSRESOLVE_QUALIFIED 0x01 /* resolve a qualified property id */ -#define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */ -#define JSRESOLVE_DETECTING 0x04 /* 'if (o.p)...' or '(o.p) ?...:...' */ -#define JSRESOLVE_DECLARING 0x08 /* var, const, or function prolog op */ -#define JSRESOLVE_CLASSNAME 0x10 /* class name used when constructing */ - -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(JSBool) -JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); - -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); - -/* - * The same, but if the property is native, return its getter and setter via - * *getterp and *setterp, respectively (and only if the out parameter pointer - * is not null). - */ -extern JS_PUBLIC_API(JSBool) -JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, - const char *name, - uintN *attrsp, JSBool *foundp, - JSPropertyOp *getterp, - JSPropertyOp *setterp); - -/* - * 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_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp); - -extern JS_PUBLIC_API(JSBool) -JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); - -extern JS_PUBLIC_API(JSBool) -JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, - uintN flags, jsval *vp); - -extern JS_PUBLIC_API(JSBool) -JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); - -extern JS_PUBLIC_API(JSBool) -JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, - 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); - -/* - * The same, but if the property is native, return its getter and setter via - * *getterp and *setterp, respectively (and only if the out parameter pointer - * is not null). - */ -extern JS_PUBLIC_API(JSBool) -JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, - const jschar *name, size_t namelen, - uintN *attrsp, JSBool *foundp, - JSPropertyOp *getterp, - JSPropertyOp *setterp); - -/* - * 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_HasUCProperty(JSContext *cx, JSObject *obj, - const jschar *name, size_t namelen, - JSBool *vp); - -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_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp); - -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); - -/* - * Create an object to iterate over enumerable properties of obj, in arbitrary - * property definition order. NB: This differs from longstanding for..in loop - * order, which uses order of property definition in obj. - */ -extern JS_PUBLIC_API(JSObject *) -JS_NewPropertyIterator(JSContext *cx, JSObject *obj); - -/* - * Return true on success with *idp containing the id of the next enumerable - * property to visit using iterobj, or JSVAL_VOID if there is no such property - * left to visit. Return false on error. - */ -extern JS_PUBLIC_API(JSBool) -JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp); - -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; - - /* XXX unspecified and unused by Mozilla code -- can we remove these? */ - 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, JSPrincipals *); - JSBool (* JS_DLL_CALLBACK subsume)(JSPrincipals *, 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(JSRuntime *rt, 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); - -/* - * Return the arity (length) of fun. - */ -extern JS_PUBLIC_API(uint16) -JS_GetFunctionArity(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(JSFunction *) -JS_DefineUCFunction(JSContext *cx, JSObject *obj, - const jschar *name, size_t namelen, 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); - -/* - * Return JS_TRUE if C (char []) strings passed via the API and internally - * are UTF-8. The source must be compiled with JS_C_STRINGS_ARE_UTF8 defined - * to get UTF-8 support. - */ -JS_PUBLIC_API(JSBool) -JS_StringsAreUTF8(); - -/* - * Character encoding support. - * - * For both JS_EncodeCharacters and JS_DecodeBytes, set *dstlenp to the size - * of the destination buffer before the call; on return, *dstlenp contains the - * number of bytes (JS_EncodeCharacters) or jschars (JS_DecodeBytes) actually - * stored. To determine the necessary destination buffer size, make a sizing - * call that passes NULL for dst. - * - * On errors, the functions report the error. In that case, *dstlenp contains - * the number of characters or bytes transferred so far. If cx is NULL, no - * error is reported on failure, and the functions simply return JS_FALSE. - * - * NB: Neither function stores an additional zero byte or jschar after the - * transcoded string. - * - * If the source has been compiled with the #define JS_C_STRINGS_ARE_UTF8 to - * enable UTF-8 interpretation of C char[] strings, then JS_EncodeCharacters - * encodes to UTF-8, and JS_DecodeBytes decodes from UTF-8, which may create - * addititional errors if the character sequence is malformed. If UTF-8 - * support is disabled, the functions deflate and inflate, respectively. - */ -JS_PUBLIC_API(JSBool) -JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, - size_t *dstlenp); - -JS_PUBLIC_API(JSBool) -JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, - size_t *dstlenp); - -/************************************************************************/ - -/* - * Locale specific string conversion callback. - */ -struct JSLocaleCallbacks { - JSLocaleToUpperCase localeToUpperCase; - JSLocaleToLowerCase localeToLowerCase; - JSLocaleCompare localeCompare; - JSLocaleToUnicode localeToUnicode; -}; - -/* - * 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); - -extern JS_PUBLIC_API(JSBool) -JS_ReportPendingException(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); - -/* - * Given a reported error's message and JSErrorReport struct pointer, throw - * the corresponding exception on cx. - */ -extern JS_PUBLIC_API(JSBool) -JS_ThrowReportedError(JSContext *cx, const char *message, - JSErrorReport *reportp); - -#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(jsword) -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 deleted file mode 100644 index 8b2c8a541..000000000 --- a/src/dom/js/jsarena.c +++ /dev/null @@ -1,579 +0,0 @@ -/* -*- 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 -#include -#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. - * - * NB: subtract nb from a->limit in the loop condition, instead of adding - * nb to a->avail, to avoid overflowing a 32-bit address space (possible - * when running a 32-bit program on a 64-bit system where the kernel maps - * the heap up against the top of the 32-bit address space). - * - * Thanks to Juergen Kreileder , who brought this up in - * https://bugzilla.mozilla.org/show_bug.cgi?id=279273. - */ - JS_ASSERT((nb & pool->mask) == 0); - for (a = pool->current; nb > a->limit || a->avail > a->limit - nb; - 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); - if (gross < nb) - return NULL; - - bp = &arena_freelist; - JS_ACQUIRE_LOCK(arena_freelist_lock); - while ((b = *bp) != NULL) { - /* - * Insist on exact arenasize match to avoid leaving alloc'able - * space after an oversized allocation as it grows. - */ - sz = JS_UPTRDIFF(b->limit, b); - if (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 NULL; - 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; - JS_ASSERT(gross > 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. We must preserve LIFO order of mark/release cursors, so we use - * the oversized-allocation arena's back pointer (or if not oversized, we - * use the result of searching the entire pool) to compute the address of - * the arena that precedes a. - */ - if (pool->current == a) - pool->current = (JSArena *) ((char *)ap - offsetof(JSArena, next)); - - /* - * 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 -#include - -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 deleted file mode 100644 index 5370f8f82..000000000 --- a/src/dom/js/jsarena.h +++ /dev/null @@ -1,313 +0,0 @@ -/* -*- 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 -#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_COMMON(p, type *, pool, sizeof(type), 0) - -#define JS_ARENA_ALLOCATE_CAST(p, type, pool, nb) \ - JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, _nb > _a->limit) - -/* - * NB: In JS_ARENA_ALLOCATE_CAST and JS_ARENA_GROW_CAST, always subtract _nb - * from a->limit rather than adding _nb to _p, to avoid overflowing a 32-bit - * address space (possible when running a 32-bit program on a 64-bit system - * where the kernel maps the heap up against the top of the 32-bit address - * space). - * - * Thanks to Juergen Kreileder , who brought this up in - * https://bugzilla.mozilla.org/show_bug.cgi?id=279273. - */ -#define JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, guard) \ - JS_BEGIN_MACRO \ - JSArena *_a = (pool)->current; \ - size_t _nb = JS_ARENA_ALIGN(pool, nb); \ - jsuword _p = _a->avail; \ - if ((guard) || _p > _a->limit - _nb) \ - _p = (jsuword)JS_ArenaAllocate(pool, _nb); \ - else \ - _a->avail = _p + _nb; \ - 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); \ - _nb = JS_ARENA_ALIGN(pool, _nb); \ - if (_a->limit >= _nb && (jsuword)(p) <= _a->limit - _nb) { \ - _a->avail = (jsuword)(p) + _nb; \ - 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 - -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 deleted file mode 100644 index ef94be4e5..000000000 --- a/src/dom/js/jsarray.c +++ /dev/null @@ -1,1901 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set sw=4 ts=8 et tw=80: - * - * ***** 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 -#include -#include "jstypes.h" -#include "jsutil.h" /* Added by JSIFY */ -#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 "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 or an XML property 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. - */ -JSBool -js_IdIsIndex(jsval 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; - } - - /* NB: id should be a string, but jsxml.c may call us with an object id. */ - if (!JSVAL_IS_STRING(id)) - return JS_FALSE; - - 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++; - } - } - - /* Ensure that all characters were consumed and we didn't overflow. */ - 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) -{ - JSTempValueRooter tvr; - jsid id; - JSBool ok; - jsint i; - - JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); - id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value); - if (ok) { - /* - * Short-circuit, because js_ValueToECMAUint32 fails when called - * during init time. - */ - if (JSVAL_IS_INT(tvr.u.value)) { - i = JSVAL_TO_INT(tvr.u.value); - *lengthp = (jsuint)i; /* jsuint cast does ToUint32 */ - } else { - ok = js_ValueToECMAUint32(cx, tvr.u.value, (uint32 *)lengthp); - } - } - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; -} - -static JSBool -IndexToValue(JSContext *cx, jsuint index, jsval *vp) -{ - if (index <= JSVAL_INT_MAX) { - *vp = INT_TO_JSVAL(index); - return JS_TRUE; - } - return js_NewDoubleValue(cx, (jsdouble)index, vp); -} - -static JSBool -IndexToId(JSContext *cx, jsuint index, jsid *idp) -{ - JSString *str; - JSAtom *atom; - - if (index <= JSVAL_INT_MAX) { - *idp = INT_TO_JSID(index); - } else { - str = js_NumberToString(cx, (jsdouble)index); - if (!str) - return JS_FALSE; - atom = js_AtomizeString(cx, str, 0); - if (!atom) - return JS_FALSE; - *idp = ATOM_TO_JSID(atom); - - } - return JS_TRUE; -} - -static JSBool -PropertyExists(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp) -{ - JSObject *obj2; - JSProperty *prop; - - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) - return JS_FALSE; - - *foundp = prop != NULL; - if (*foundp) { - OBJ_DROP_PROPERTY(cx, obj2, prop); - } - - return JS_TRUE; -} - -#define JSID_HOLE JSVAL_NULL - -static JSBool -IndexToExistingId(JSContext *cx, JSObject *obj, jsuint index, jsid *idp) -{ - JSBool exists; - - if (!IndexToId(cx, index, idp)) - return JS_FALSE; - if (!PropertyExists(cx, obj, *idp, &exists)) - return JS_FALSE; - if (!exists) - *idp = JSID_HOLE; - 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 = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - return OBJ_SET_PROPERTY(cx, obj, id, &v); -} - -JSBool -js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) -{ - JSErrorReporter older; - JSTempValueRooter tvr; - jsid id; - JSBool ok; - - older = JS_SetErrorReporter(cx, NULL); - JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); - id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value); - JS_SetErrorReporter(cx, older); - if (ok) - ok = ValueIsLength(cx, tvr.u.value, lengthp); - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; -} - -/* - * 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 (!js_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 (JS_VERSION_IS_1_2(cx)) { - 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; - jsuint length, index; - jschar *chars, *ochars; - size_t nchars, growth, seplen, tmplen; - const jschar *sepstr; - JSString *str; - JSHashEntry *he; - JSTempValueRooter tvr; - JSAtom *atom; - int stackDummy; - - if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); - return JS_FALSE; - } - - ok = js_GetLengthProperty(cx, obj, &length); - if (!ok) - return JS_FALSE; - - 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); - - /* Use rval to locally root each element value as we loop and convert. */ -#define v (*rval) - - v = JSVAL_NULL; - for (index = 0; index < length; index++) { - ok = JS_GetElement(cx, obj, index, &v); - if (!ok) - goto done; - - if ((!literalize || JS_VERSION_IS_1_2(cx)) && - (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v))) { - str = cx->runtime->emptyString; - } else { - if (localeString) { - atom = cx->runtime->atomState.toLocaleStringAtom; - JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); - ok = js_ValueToObject(cx, v, &tvr.u.object) && - js_TryMethod(cx, tvr.u.object, atom, 0, NULL, &v); - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ok) - goto done; - 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. */ - tmplen = JSSTRING_LENGTH(str); - growth = (nchars + (sepstr ? seplen : 0) + tmplen + 3 + 1); - if (nchars > growth || tmplen > growth || - growth > (size_t)-1 / sizeof(jschar)) { - if (chars) { - free(chars); - chars = NULL; - } - JS_ReportOutOfMemory(cx); - goto done; - } - growth *= 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); - - 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; - } - -#undef v - - 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 = JS_VERSION_IS_1_2(cx); - 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++) { - JS_ASSERT(vector[index] != JSVAL_HOLE); - - 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 = ATOM_TO_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 *tmproot, *tmproot2; - JSBool idexists, id2exists, ok; - - if (!js_GetLengthProperty(cx, obj, &len)) - return JS_FALSE; - - /* - * When len > JSVAL_INT_MAX + 1 the loop below accesses indexes greater - * than JSVAL_INT_MAX. For such indexes the corresponding ids are atoms. - * We use JS_KEEP_ATOMS to protect them against GC since OBJ_GET_PROPERTY - * can potentially execute an arbitrary script. See bug 341956. - * - * After this point control must flow through label out: to exit. - */ - if (len > JSVAL_INT_MAX + 1) - JS_KEEP_ATOMS(cx->runtime); - - /* - * Use argv[argc] and argv[argc + 1] as local roots to hold temporarily - * array elements for GC-safe swap. - */ - tmproot = argv + argc; - tmproot2 = argv + argc + 1; - half = len / 2; - for (i = 0; i < half; i++) { - /* - * Get both values while checking for holes to make sure they don't - * get filled. - */ - if (!IndexToId(cx, i, &id)) - goto bad; - if (!PropertyExists(cx, obj, id, &idexists)) - goto bad; - if (idexists && !OBJ_GET_PROPERTY(cx, obj, id, tmproot)) - goto bad; - - if (!IndexToId(cx, len - i - 1, &id2)) - goto bad; - if (!PropertyExists(cx, obj, id2, &id2exists)) - goto bad; - if (id2exists && !OBJ_GET_PROPERTY(cx, obj, id2, tmproot2)) - goto bad; - - /* Exchange the values. */ - if (idexists) { - if (!OBJ_SET_PROPERTY(cx, obj, id2, tmproot)) - goto bad; - } else { - if (!OBJ_DELETE_PROPERTY(cx, obj, id2, tmproot)) - goto bad; - } - if (id2exists) { - if (!OBJ_SET_PROPERTY(cx, obj, id, tmproot2)) - goto bad; - } else { - if (!OBJ_DELETE_PROPERTY(cx, obj, id, tmproot2)) - goto bad; - } - } - ok = JS_TRUE; - - out: - if (len > JSVAL_INT_MAX + 1) - JS_UNKEEP_ATOMS(cx->runtime); - *rval = OBJECT_TO_JSVAL(obj); - return ok; - - bad: - ok = JS_FALSE; - goto out; -} - -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 -} - -void -js_HeapSort(void *vec, size_t nel, void *pivot, size_t elsize, - JSComparator cmp, void *arg) -{ - HSortArgs hsa; - size_t i; - - 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); -} - -typedef struct CompareArgs { - JSContext *context; - jsval fval; - jsval *localroot; /* need one local root, for sort_compare */ - 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], special; - JSBool ok; - - fval = ca->fval; - - /* - * By ECMA 262, 15.4.4.11, existence of the property with value undefined - * takes precedence over an undefined property (which we call a "hole"). - */ - if (av == JSVAL_HOLE || bv == JSVAL_HOLE) - special = JSVAL_HOLE; - else if (av == JSVAL_VOID || bv == JSVAL_VOID) - special = JSVAL_VOID; - else - special = JSVAL_NULL; - - if (special != JSVAL_NULL) { - if (av == bv) - cmp = 0; - else if (av != special) - cmp = -1; - else - cmp = 1; - } else if (fval == JSVAL_NULL) { - JSString *astr, *bstr; - - if (av == bv) { - cmp = 0; - } else { - /* - * Set our local root to astr in case the second js_ValueToString - * displaces the newborn root in cx, and the GC nests under that - * call. Don't bother guarding the local root store with an astr - * non-null test. If we tag null as a string, the GC will untag, - * null-test, and avoid dereferencing null. - */ - astr = js_ValueToString(cx, av); - *ca->localroot = STRING_TO_JSVAL(astr); - if (astr && (bstr = js_ValueToString(cx, bv))) - 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, ca->localroot); - if (ok) { - ok = js_ValueToNumber(cx, *ca->localroot, &cmp); - - /* Clamp cmp to -1, 0, 1. */ - if (ok) { - 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; - } - } - } - if (!ok) - 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)); -} - -static JSBool -array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval fval, *vec, *pivotroot; - CompareArgs ca; - jsuint len, newlen, i; - JSStackFrame *fp; - 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; - } - - /* - * We need a temporary array of len jsvals to hold elements of the array. - * Check that its size does not overflow size_t, which would allow for - * indexing beyond the end of the malloc'd vector. - */ - if (len > ((size_t) -1) / sizeof(jsval)) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - nbytes = ((size_t) len) * sizeof(jsval); - - vec = (jsval *) JS_malloc(cx, nbytes); - if (!vec) - return JS_FALSE; - - /* Root vec, clearing it first in case a GC nests while we're filling it. */ - memset(vec, 0, nbytes); - fp = cx->fp; - fp->vars = vec; - fp->nvars = len; - - newlen = 0; - for (i = 0; i < len; i++) { - ca.status = IndexToExistingId(cx, obj, i, &id); - if (!ca.status) - goto out; - - if (id == JSID_HOLE) { - vec[i] = JSVAL_HOLE; - all_strings = JS_FALSE; - continue; - } - newlen++; - - 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.localroot = argv + argc; /* local GC root for temporary string */ - pivotroot = argv + argc + 1; /* local GC root for pivot val */ - ca.status = JS_TRUE; - js_HeapSort(vec, (size_t) len, pivotroot, sizeof(jsval), - all_strings ? sort_compare_strings : sort_compare, - &ca); - - if (ca.status) { - ca.status = InitArrayElements(cx, obj, newlen, vec); - if (ca.status) - *rval = OBJECT_TO_JSVAL(obj); - - /* Re-create any holes that sorted to the end of the array. */ - while (len > newlen) { - jsval junk; - - if (!IndexToId(cx, --len, &id)) - return JS_FALSE; - if (!OBJ_DELETE_PROPERTY(cx, obj, id, &junk)) - return JS_FALSE; - } - } - -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 (JS_VERSION_IS_1_2(cx)) { - *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; - JSBool ok; - jsval junk; - - if (!js_GetLengthProperty(cx, obj, &index)) - return JS_FALSE; - if (index > 0) { - index--; - - /* Get the to-be-deleted property's value into rval. */ - if (!IndexToId(cx, index, &id)) - return JS_FALSE; - - /* See comments in array_reverse. */ - if (index > JSVAL_INT_MAX) - JS_KEEP_ATOMS(cx->runtime); - ok = OBJ_GET_PROPERTY(cx, obj, id, rval) && - OBJ_DELETE_PROPERTY(cx, obj, id, &junk); - if (index > JSVAL_INT_MAX) - JS_UNKEEP_ATOMS(cx->runtime); - if (!ok) - 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 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 (!OBJ_GET_PROPERTY(cx, obj, id, &argv[0])) - return JS_FALSE; - - /* Get id after value to avoid nested GC hazards. */ - if (!IndexToId(cx, i - 1, &id2)) - return JS_FALSE; - if (!OBJ_SET_PROPERTY(cx, obj, id2, &argv[0])) - return JS_FALSE; - } - } - - /* - * Delete the only or the last element. We recreate id when it is an - * atom to protect against a nested GC during the last iteration. - */ - if (length > JSVAL_INT_MAX && !IndexToId(cx, length, &id)) - return JS_FALSE; - 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 *vp, junk; - - 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; - vp = argv + argc; - while (last--) { - if (!IndexToExistingId(cx, obj, last, &id)) - return JS_FALSE; - if (id != JSID_HOLE) { - if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) - return JS_FALSE; - } - - /* Get id after value to avoid nested GC hazards. */ - if (!IndexToId(cx, last + argc, &id2)) - return JS_FALSE; - if (id == JSID_HOLE) { - if (!OBJ_DELETE_PROPERTY(cx, obj, id2, &junk)) - return JS_FALSE; - } else { - if (!OBJ_SET_PROPERTY(cx, obj, id2, vp)) - 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) -{ - jsval *vp, junk; - jsuint length, begin, end, count, delta, last; - jsdouble d; - jsid id, id2; - JSObject *obj2; - uintN i; - - /* - * Nothing to do if no args. Otherwise point vp at our one explicit local - * root and get length. - */ - if (argc == 0) - return JS_TRUE; - vp = argv + argc; - 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 && JS_VERSION_IS_1_2(cx)) { - /* - * 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 (!JS_VERSION_IS_1_2(cx) || 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 (!IndexToExistingId(cx, obj, last, &id)) - return JS_FALSE; - if (id == JSID_HOLE) - continue; /* don't fill holes in the new array */ - if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) - return JS_FALSE; - - /* Get id after value to avoid nested GC hazards. */ - if (!IndexToId(cx, last - begin, &id2)) - return JS_FALSE; - if (!OBJ_SET_PROPERTY(cx, obj2, id2, vp)) - return JS_FALSE; - } - - if (!js_SetLengthProperty(cx, obj2, end - begin)) - 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 (!IndexToExistingId(cx, obj, last, &id)) - return JS_FALSE; - if (id != JSID_HOLE) { - if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) - return JS_FALSE; - } - - /* Get id after value to avoid nested GC hazards. */ - if (!IndexToId(cx, last + delta, &id2)) - return JS_FALSE; - if (id != JSID_HOLE) { - if (!OBJ_SET_PROPERTY(cx, obj, id2, vp)) - return JS_FALSE; - } else { - if (!OBJ_DELETE_PROPERTY(cx, obj, id2, &junk)) - return JS_FALSE; - } - } - length += delta; - } else if (argc < count) { - delta = count - (jsuint)argc; - for (last = end; last < length; last++) { - if (!IndexToExistingId(cx, obj, last, &id)) - return JS_FALSE; - if (id != JSID_HOLE) { - if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) - return JS_FALSE; - } - - /* Get id after value to avoid nested GC hazards. */ - if (!IndexToId(cx, last - delta, &id2)) - return JS_FALSE; - if (id != JSID_HOLE) { - if (!OBJ_SET_PROPERTY(cx, obj, id2, vp)) - return JS_FALSE; - } else { - if (!OBJ_DELETE_PROPERTY(cx, obj, id2, &junk)) - 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) -{ - jsval *vp, v; - JSObject *nobj, *aobj; - jsuint length, alength, slot; - uintN i; - jsid id, id2; - - /* Hoist the explicit local root address computation. */ - vp = argv + argc; - - /* 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, - ATOM_TO_JSID(cx->runtime->atomState - .lengthAtom), - vp)) { - return JS_FALSE; - } - if (!ValueIsLength(cx, *vp, &alength)) - return JS_FALSE; - for (slot = 0; slot < alength; slot++) { - if (!IndexToExistingId(cx, aobj, slot, &id)) - return JS_FALSE; - if (id == JSID_HOLE) { - /* - * Per ECMA 262, 15.4.4.4, step 9, ignore non-existent - * properties. - */ - continue; - } - if (!OBJ_GET_PROPERTY(cx, aobj, id, vp)) - return JS_FALSE; - - /* Get id after value to avoid nested GC hazards. */ - if (!IndexToId(cx, length + slot, &id2)) - return JS_FALSE; - if (!OBJ_SET_PROPERTY(cx, nobj, id2, vp)) - return JS_FALSE; - } - length += alength; - continue; - } - } - - *vp = v; - if (!IndexToId(cx, length, &id)) - return JS_FALSE; - if (!OBJ_SET_PROPERTY(cx, nobj, id, vp)) - return JS_FALSE; - length++; - } - - return js_SetLengthProperty(cx, nobj, length); -} - -static JSBool -array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval *vp; - JSObject *nobj; - jsuint length, begin, end, slot; - jsdouble d; - jsid id, id2; - - /* Hoist the explicit local root address computation. */ - vp = argv + argc; - - /* 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); - - 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; - } - } - - if (begin > end) - begin = end; - - for (slot = begin; slot < end; slot++) { - if (!IndexToExistingId(cx, obj, slot, &id)) - return JS_FALSE; - if (id == JSID_HOLE) - continue; - if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) - return JS_FALSE; - - /* Get id after value to avoid nested GC hazards. */ - if (!IndexToId(cx, slot - begin, &id2)) - return JS_FALSE; - if (!OBJ_SET_PROPERTY(cx, nobj, id2, vp)) - return JS_FALSE; - } - return js_SetLengthProperty(cx, nobj, end - begin); -} -#endif /* JS_HAS_SEQUENCE_OPS */ - -#if JS_HAS_ARRAY_EXTRAS - -static JSBool -array_indexOfHelper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval, JSBool isLast) -{ - jsuint length, i, stop; - jsint direction; - - if (!js_GetLengthProperty(cx, obj, &length)) - return JS_FALSE; - if (length == 0) - goto not_found; - - if (argc <= 1) { - i = isLast ? length - 1 : 0; - } else { - jsdouble start; - - if (!js_ValueToNumber(cx, argv[1], &start)) - return JS_FALSE; - start = js_DoubleToInteger(start); - if (start < 0) { - start += length; - i = (start < 0) ? 0 : (jsuint)start; - } else if (start >= length) { - i = length - 1; - } else { - i = (jsuint)start; - } - } - - if (isLast) { - stop = 0; - direction = -1; - } else { - stop = length - 1; - direction = 1; - } - - for (;;) { - jsid id; - jsval v; - - if (!IndexToExistingId(cx, obj, (jsuint)i, &id)) - return JS_FALSE; - if (id != JSID_HOLE) { - if (!OBJ_GET_PROPERTY(cx, obj, id, &v)) - return JS_FALSE; - if (js_StrictlyEqual(v, argv[0])) - return js_NewNumberValue(cx, i, rval); - } - - if (i == stop) - goto not_found; - i += direction; - } - - not_found: - *rval = INT_TO_JSVAL(-1); - return JS_TRUE; -} - -static JSBool -array_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return array_indexOfHelper(cx, obj, argc, argv, rval, JS_FALSE); -} - -static JSBool -array_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return array_indexOfHelper(cx, obj, argc, argv, rval, JS_TRUE); -} - -/* Order is important; extras that use a caller's predicate must follow MAP. */ -typedef enum ArrayExtraMode { - FOREACH, - MAP, - FILTER, - SOME, - EVERY -} ArrayExtraMode; - -static JSBool -array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, - ArrayExtraMode mode) -{ - jsval *vp, *sp, *origsp, *oldsp; - jsuint length, newlen, i; - JSObject *callable, *thisp, *newarr; - void *mark; - JSStackFrame *fp; - JSBool ok, b; - - /* Hoist the explicit local root address computation. */ - vp = argv + argc; - - if (!js_GetLengthProperty(cx, obj, &length)) - return JS_FALSE; - - /* - * First, get or compute our callee, so that we error out consistently - * when passed a non-callable object. - */ - callable = js_ValueToCallableObject(cx, &argv[0], 0); - if (!callable) - return JS_FALSE; - - /* - * Set our initial return condition, used for zero-length array cases - * (and pre-size our map return to match our known length, for all cases). - */ -#ifdef __GNUC__ /* quell GCC overwarning */ - newlen = 0; - newarr = NULL; - ok = JS_TRUE; -#endif - switch (mode) { - case MAP: - case FILTER: - newlen = (mode == MAP) ? length : 0; - newarr = js_NewArrayObject(cx, newlen, NULL); - if (!newarr) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(newarr); - break; - case SOME: - *rval = JSVAL_FALSE; - break; - case EVERY: - *rval = JSVAL_TRUE; - break; - case FOREACH: - break; - } - - if (length == 0) - return JS_TRUE; - - if (argc > 1) { - if (!js_ValueToObject(cx, argv[1], &thisp)) - return JS_FALSE; - argv[1] = OBJECT_TO_JSVAL(thisp); - } else { - thisp = NULL; - } - - /* We call with 3 args (value, index, array), plus room for rval. */ - origsp = js_AllocStack(cx, 2 + 3 + 1, &mark); - if (!origsp) - return JS_FALSE; - - /* Lift current frame to include our args. */ - fp = cx->fp; - oldsp = fp->sp; - - for (i = 0; i < length; i++) { - jsid id; - jsval rval2; - - ok = IndexToExistingId(cx, obj, i, &id); - if (!ok) - break; - if (id == JSID_HOLE) - continue; - ok = OBJ_GET_PROPERTY(cx, obj, id, vp); - if (!ok) - break; - - /* - * Push callable and 'this', then args. We must do this for every - * iteration around the loop since js_Invoke uses origsp[0] for rval - * storage and some native functions use origsp[1] for local rooting. - */ - sp = origsp; - *sp++ = OBJECT_TO_JSVAL(callable); - *sp++ = OBJECT_TO_JSVAL(thisp); - *sp++ = *vp; - *sp++ = INT_TO_JSVAL(i); - *sp++ = OBJECT_TO_JSVAL(obj); - - /* Do the call. */ - fp->sp = sp; - ok = js_Invoke(cx, 3, JSINVOKE_INTERNAL); - rval2 = fp->sp[-1]; - fp->sp = oldsp; - if (!ok) - break; - - if (mode > MAP) { - if (rval2 == JSVAL_NULL) { - b = JS_FALSE; - } else if (JSVAL_IS_BOOLEAN(rval2)) { - b = JSVAL_TO_BOOLEAN(rval2); - } else { - ok = js_ValueToBoolean(cx, rval2, &b); - if (!ok) - goto out; - } - } - - switch (mode) { - case FOREACH: - break; - case MAP: - /* - * We reconstruct id once again when it is a GC thing since scripts - * can trigger GC that collects it. See bug 341956. - */ - if (i > JSVAL_INT_MAX) { - ok = IndexToId(cx, i, &id); - if (!ok) - goto out; - } - ok = OBJ_SET_PROPERTY(cx, newarr, id, &rval2); - if (!ok) - goto out; - break; - case FILTER: - if (!b) - break; - /* Filter passed *vp, push as result. */ - ok = IndexToId(cx, newlen++, &id); - if (!ok) - goto out; - ok = OBJ_SET_PROPERTY(cx, newarr, id, vp); - if (!ok) - goto out; - break; - case SOME: - if (b) { - *rval = JSVAL_TRUE; - goto out; - } - break; - case EVERY: - if (!b) { - *rval = JSVAL_FALSE; - goto out; - } - break; - } - } - - out: - js_FreeStack(cx, mark); - if (ok && mode == FILTER) - ok = js_SetLengthProperty(cx, newarr, newlen); - return ok; -} - -static JSBool -array_forEach(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return array_extra(cx, obj, argc, argv, rval, FOREACH); -} - -static JSBool -array_map(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return array_extra(cx, obj, argc, argv, rval, MAP); -} - -static JSBool -array_filter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return array_extra(cx, obj, argc, argv, rval, FILTER); -} - -static JSBool -array_some(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return array_extra(cx, obj, argc, argv, rval, SOME); -} - -static JSBool -array_every(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - return array_extra(cx, obj, argc, argv, rval, EVERY); -} -#endif - -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,JSFUN_GENERIC_NATIVE,0}, - {"reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE,2}, - {"sort", array_sort, 1,JSFUN_GENERIC_NATIVE,2}, -#endif -#if JS_HAS_MORE_PERL_FUN - {"push", array_push, 1,JSFUN_GENERIC_NATIVE,0}, - {"pop", array_pop, 0,JSFUN_GENERIC_NATIVE,0}, - {"shift", array_shift, 0,JSFUN_GENERIC_NATIVE,1}, - {"unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE,1}, - {"splice", array_splice, 2,JSFUN_GENERIC_NATIVE,1}, -#endif - - /* Python-esque sequence methods. */ -#if JS_HAS_SEQUENCE_OPS - {"concat", array_concat, 1,JSFUN_GENERIC_NATIVE,1}, - {"slice", array_slice, 2,JSFUN_GENERIC_NATIVE,1}, -#endif - -#if JS_HAS_ARRAY_EXTRAS - {"indexOf", array_indexOf, 1,JSFUN_GENERIC_NATIVE,0}, - {"lastIndexOf", array_lastIndexOf, 1,JSFUN_GENERIC_NATIVE,0}, - {"forEach", array_forEach, 1,JSFUN_GENERIC_NATIVE,1}, - {"map", array_map, 1,JSFUN_GENERIC_NATIVE,1}, - {"filter", array_filter, 1,JSFUN_GENERIC_NATIVE,1}, - {"some", array_some, 1,JSFUN_GENERIC_NATIVE,1}, - {"every", array_every, 1,JSFUN_GENERIC_NATIVE,1}, -#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 (JS_VERSION_IS_1_2(cx)) { - 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 deleted file mode 100644 index 0f43bee07..000000000 --- a/src/dom/js/jsarray.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- 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 JSBool -js_IdIsIndex(jsval id, jsuint *indexp); - -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 void -js_HeapSort(void *vec, size_t nel, void *pivot, 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 deleted file mode 100644 index 6de628aef..000000000 --- a/src/dom/js/jsatom.c +++ /dev/null @@ -1,980 +0,0 @@ -/* -*- 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 -#include -#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 "jsconfig.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) -{ - return js_ValueToPrintableString(cx, ATOM_KEY(atom)); -} - -#if JS_HAS_ERROR_EXCEPTIONS -extern const char js_Error_str[]; /* trivial, from jsexn.h */ -#endif - -/* - * 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", - js_object_str, - "function", - "string", - "number", - "boolean", - "null", - "xml", -}; - -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_Namespace_str[] = "Namespace"; -const char js_Number_str[] = "Number"; -const char js_Object_str[] = "Object"; -const char js_QName_str[] = "QName"; -const char js_RegExp_str[] = "RegExp"; -const char js_Script_str[] = "Script"; -const char js_String_str[] = "String"; -const char js_XML_str[] = "XML"; -const char js_File_str[] = "File"; -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_each_str[] = "each"; -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_object_str[] = "object"; -const char js_parent_str[] = "__parent__"; -const char js_private_str[] = "private"; -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"; - -#if JS_HAS_XML_SUPPORT -const char js_etago_str[] = ""; -const char js_qualifier_str[] = "::"; -const char js_space_str[] = " "; -const char js_stago_str[] = "<"; -const char js_star_str[] = "*"; -const char js_starQualifier_str[] = "*::"; -const char js_tagc_str[] = ">"; -const char js_xml_str[] = "xml"; -#endif - -#ifdef NARCISSUS -const char js_call_str[] = "__call__"; -const char js_construct_str[] = "__construct__"; -const char js_hasInstance_str[] = "__hasInstance__"; -const char js_ExecutionContext_str[] = "ExecutionContext"; -const char js_current_str[] = "current"; -#endif - -#define HASH_OBJECT(o) (JS_PTR_TO_UINT32(o) >> JSVAL_TAGBITS) -#define HASH_INT(i) ((JSHashNumber)(i)) -#define HASH_DOUBLE(dp) ((JSDOUBLE_HI32(*dp) ^ JSDOUBLE_LO32(*dp))) -#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); -#if JS_HAS_ERROR_EXCEPTIONS - FROB(ErrorAtom, js_Error_str); -#endif - FROB(FunctionAtom, js_Function_str); - FROB(MathAtom, js_Math_str); - FROB(NamespaceAtom, js_Namespace_str); - FROB(NumberAtom, js_Number_str); - FROB(ObjectAtom, js_Object_str); - FROB(QNameAtom, js_QName_str); - FROB(RegExpAtom, js_RegExp_str); - FROB(ScriptAtom, js_Script_str); - FROB(StringAtom, js_String_str); - FROB(XMLAtom, js_XML_str); - FROB(FileAtom, js_File_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(eachAtom, js_each_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); - -#if JS_HAS_XML_SUPPORT - FROB(etagoAtom, js_etago_str); - FROB(namespaceAtom, js_namespace_str); - FROB(ptagcAtom, js_ptagc_str); - FROB(qualifierAtom, js_qualifier_str); - FROB(spaceAtom, js_space_str); - FROB(stagoAtom, js_stago_str); - FROB(starAtom, js_star_str); - FROB(starQualifierAtom, js_starQualifier_str); - FROB(tagcAtom, js_tagc_str); - FROB(xmlAtom, js_xml_str); -#endif - -#ifdef NARCISSUS - FROB(callAtom, js_call_str); - FROB(constructAtom, js_construct_str); - FROB(hasInstanceAtom, js_hasInstance_str); - FROB(ExecutionContextAtom, js_ExecutionContext_str); - FROB(currentAtom, js_current_str); -#endif - -#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 = atom->entry.value = 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; -} - -/* - * To put an atom into the hidden subspace. XOR its keyHash with this value, - * which is (sqrt(2)-1) in 32-bit fixed point. - */ -#define HIDDEN_ATOM_SUBSPACE_KEYHASH 0x6A09E667 - -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); - if (flags & ATOM_HIDDEN) - keyHash ^= HIDDEN_ATOM_SUBSPACE_KEYHASH; - 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 | ATOM_HIDDEN); - 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]; - size_t inflatedLength = ATOMIZE_BUF_MAX - 1; - - if (length < ATOMIZE_BUF_MAX) { - js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength); - inflated[inflatedLength] = 0; - chars = inflated; - } else { - inflatedLength = length; - chars = js_InflateString(cx, bytes, &inflatedLength); - if (!chars) - return NULL; - flags |= ATOM_NOCOPY; - } - - str = ALIGN(buf, JSString); - - str->chars = chars; - str->length = inflatedLength; - 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 < 10) { - /* 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(al->count + 1, js_hash_atom_ptr, - JS_CompareValues, JS_CompareValues, - &temp_alloc_ops, cx); - if (!al->table) - return NULL; - - /* - * Set ht->nentries explicitly, because we are moving entries - * from al to ht, not calling JS_HashTable(Raw|)Add. - */ - al->table->nentries = al->count; - - /* 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 deleted file mode 100644 index f8ce3f90f..000000000 --- a/src/dom/js/jsatom.h +++ /dev/null @@ -1,468 +0,0 @@ -/* -*- 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 -#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_HIDDEN 0x08 /* atom is in special hidden subspace */ -#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 or - unhidden atom if ATOM_HIDDEN */ - 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) JS_PTR_TO_UINT32((ale)->entry.value)) -#define ALE_JSOP(ale) ((JSOp) (ale)->entry.value) -#define ALE_VALUE(ale) ((jsval) (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 = JS_UINT32_TO_PTR(index)) -#define ALE_SET_JSOP(ale,op) ((ale)->entry.value = JS_UINT32_TO_PTR(op)) -#define ALE_SET_VALUE(ale,val) ((ale)->entry.value = (JSHashEntry *)(val)) -#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 */ - - /* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */ - JSAtom *emptyAtom; - - /* 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 *NamespaceAtom; - JSAtom *NumberAtom; - JSAtom *ObjectAtom; - JSAtom *QNameAtom; - JSAtom *RegExpAtom; - JSAtom *ScriptAtom; - JSAtom *StringAtom; - JSAtom *XMLAtom; - JSAtom *FileAtom; - JSAtom *anonymousAtom; - JSAtom *argumentsAtom; - JSAtom *arityAtom; - JSAtom *calleeAtom; - JSAtom *callerAtom; - JSAtom *classPrototypeAtom; - JSAtom *constructorAtom; - JSAtom *countAtom; - JSAtom *eachAtom; - JSAtom *etagoAtom; - JSAtom *evalAtom; - JSAtom *getAtom; - JSAtom *getterAtom; - JSAtom *indexAtom; - JSAtom *inputAtom; - JSAtom *lengthAtom; - JSAtom *nameAtom; - JSAtom *namespaceAtom; - JSAtom *noSuchMethodAtom; - JSAtom *parentAtom; - JSAtom *protoAtom; - JSAtom *ptagcAtom; - JSAtom *qualifierAtom; - JSAtom *setAtom; - JSAtom *setterAtom; - JSAtom *spaceAtom; - JSAtom *stagoAtom; - JSAtom *starAtom; - JSAtom *starQualifierAtom; - JSAtom *tagcAtom; - JSAtom *toLocaleStringAtom; - JSAtom *toSourceAtom; - JSAtom *toStringAtom; - JSAtom *valueOfAtom; - JSAtom *xmlAtom; - - /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */ - struct { - JSAtom *AnyNameAtom; - JSAtom *AttributeNameAtom; - JSAtom *EvalErrorAtom; - JSAtom *InfinityAtom; - JSAtom *InternalErrorAtom; - JSAtom *NaNAtom; - JSAtom *RangeErrorAtom; - JSAtom *ReferenceErrorAtom; - JSAtom *SyntaxErrorAtom; - JSAtom *TypeErrorAtom; - JSAtom *URIErrorAtom; - JSAtom *XMLListAtom; - JSAtom *decodeURIAtom; - JSAtom *decodeURIComponentAtom; - JSAtom *defineGetterAtom; - JSAtom *defineSetterAtom; - JSAtom *encodeURIAtom; - JSAtom *encodeURIComponentAtom; - JSAtom *escapeAtom; - JSAtom *functionNamespaceURIAtom; - JSAtom *hasOwnPropertyAtom; - JSAtom *isFiniteAtom; - JSAtom *isNaNAtom; - JSAtom *isPrototypeOfAtom; - JSAtom *isXMLNameAtom; - 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 -#ifdef NARCISSUS - JSAtom *callAtom; - JSAtom *constructAtom; - JSAtom *hasInstanceAtom; - JSAtom *ExecutionContextAtom; - JSAtom *currentAtom; -#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_Namespace_str[]; -extern const char js_Number_str[]; -extern const char js_Object_str[]; -extern const char js_QName_str[]; -extern const char js_RegExp_str[]; -extern const char js_Script_str[]; -extern const char js_String_str[]; -extern const char js_XML_str[]; -extern const char js_File_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_etago_str[]; -extern const char js_each_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_namespace_str[]; -extern const char js_noSuchMethod_str[]; -extern const char js_object_str[]; -extern const char js_parent_str[]; -extern const char js_private_str[]; -extern const char js_proto_str[]; -extern const char js_ptagc_str[]; -extern const char js_qualifier_str[]; -extern const char js_setter_str[]; -extern const char js_set_str[]; -extern const char js_space_str[]; -extern const char js_stago_str[]; -extern const char js_star_str[]; -extern const char js_starQualifier_str[]; -extern const char js_tagc_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[]; -extern const char js_xml_str[]; - -#ifdef NARCISSUS -extern const char js_call_str[]; -extern const char js_construct_str[]; -extern const char js_hasInstance_str[]; -extern const char js_ExecutionContext_str[]; -extern const char js_current_str[]; -#endif - -/* - * 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/jsbit.h b/src/dom/js/jsbit.h deleted file mode 100644 index db41acf9f..000000000 --- a/src/dom/js/jsbit.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 33d5c507e..000000000 --- a/src/dom/js/jsbool.c +++ /dev/null @@ -1,215 +0,0 @@ -/* -*- 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" - -JSClass js_BooleanClass = { - "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, &js_BooleanClass, 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))", - js_BooleanClass.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, &js_BooleanClass, 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, &js_BooleanClass, 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} -}; - -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, &js_BooleanClass, 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, &js_BooleanClass, 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 (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { - b = JS_FALSE; - } else if (JSVAL_IS_OBJECT(v)) { - if (!JS_VERSION_IS_ECMA(cx)) { - 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 { - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); - b = JSVAL_TO_BOOLEAN(v); - } - - *bp = b; - return JS_TRUE; -} diff --git a/src/dom/js/jsbool.h b/src/dom/js/jsbool.h deleted file mode 100644 index 770b94c6d..000000000 --- a/src/dom/js/jsbool.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- 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 - -/* - * Crypto-booleans, not visible to script but used internally by the engine. - * - * JSVAL_HOLE is a useful value for identifying a hole in an array. It's also - * used in the interpreter to represent "no exception pending". In general it - * can be used to represent "no value". - */ -#define JSVAL_HOLE BOOLEAN_TO_JSVAL(2) - -extern JSClass js_BooleanClass; - -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 deleted file mode 100644 index 604ec0ec9..000000000 --- a/src/dom/js/jsclist.h +++ /dev/null @@ -1,139 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 43041f97b..000000000 --- a/src/dom/js/jscntxt.c +++ /dev/null @@ -1,1073 +0,0 @@ -/* -*- 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 -#include -#include -#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" - -void -js_OnVersionChange(JSContext *cx) -{ -#if !JS_BUG_FALLIBLE_EQOPS - if (JS_VERSION_IS_1_2(cx)) { - 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 */ -} - -void -js_SetVersion(JSContext *cx, JSVersion version) -{ - cx->version = version; - js_OnVersionChange(cx); -} - -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) { - /* - * Both atomState and the scriptFilenameTable may be left over from a - * previous episode of non-zero contexts alive in rt, so don't re-init - * either table if it's not necessary. Just repopulate atomState with - * well-known internal atoms, and with the reserved identifiers added - * by the scanner. - */ - ok = (rt->atomState.liveAtoms == 0) - ? js_InitAtomState(cx, &rt->atomState) - : js_InitPinnedAtoms(cx, &rt->atomState); - if (ok) - ok = js_InitScanner(cx); - if (ok && !rt->scriptFilenameTable) - ok = js_InitRuntimeScriptState(rt); - 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; - JSLocalRootStack *lrs; - JSLocalRootChunk *lrc; - - 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); - - /* Also free the script filename table if it exists and is empty. */ - if (rt->scriptFilenameTable && rt->scriptFilenameTable->nentries == 0) - js_FinishRuntimeScriptState(rt); - - /* 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; - } - - lrs = cx->localRootStack; - if (lrs) { - while ((lrc = lrs->topChunk) != &lrs->firstChunk) { - lrs->topChunk = lrc->down; - JS_free(cx, lrc); - } - JS_free(cx, lrs); - } - - /* 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; -} - -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)JS_PTR_TO_UINT32(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 -}; - -JSBool -js_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; -} - -void -js_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 js_StartResolving. - */ - table = cx->resolvingTable; - if (!entry || table->generation != generation) { - entry = (JSResolvingEntry *) - JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP); - } - JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)); - 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); -} - -JSBool -js_EnterLocalRootScope(JSContext *cx) -{ - JSLocalRootStack *lrs; - int mark; - - lrs = cx->localRootStack; - if (!lrs) { - lrs = (JSLocalRootStack *) JS_malloc(cx, sizeof *lrs); - if (!lrs) - return JS_FALSE; - lrs->scopeMark = JSLRS_NULL_MARK; - lrs->rootCount = 0; - lrs->topChunk = &lrs->firstChunk; - lrs->firstChunk.down = NULL; - cx->localRootStack = lrs; - } - - /* Push lrs->scopeMark to save it for restore when leaving. */ - mark = js_PushLocalRoot(cx, lrs, INT_TO_JSVAL(lrs->scopeMark)); - if (mark < 0) - return JS_FALSE; - lrs->scopeMark = (uint32) mark; - return JS_TRUE; -} - -void -js_LeaveLocalRootScope(JSContext *cx) -{ - JSLocalRootStack *lrs; - unsigned mark, m, n; - JSLocalRootChunk *lrc; - - /* Defend against buggy native callers. */ - lrs = cx->localRootStack; - JS_ASSERT(lrs && lrs->rootCount != 0); - if (!lrs || lrs->rootCount == 0) - return; - - mark = lrs->scopeMark; - JS_ASSERT(mark != JSLRS_NULL_MARK); - if (mark == JSLRS_NULL_MARK) - return; - - /* Free any chunks being popped by this leave operation. */ - m = mark >> JSLRS_CHUNK_SHIFT; - n = (lrs->rootCount - 1) >> JSLRS_CHUNK_SHIFT; - while (n > m) { - lrc = lrs->topChunk; - JS_ASSERT(lrc != &lrs->firstChunk); - lrs->topChunk = lrc->down; - JS_free(cx, lrc); - --n; - } - - /* Pop the scope, restoring lrs->scopeMark. */ - lrc = lrs->topChunk; - m = mark & JSLRS_CHUNK_MASK; - lrs->scopeMark = (uint32) JSVAL_TO_INT(lrc->roots[m]); - lrc->roots[m] = JSVAL_NULL; - lrs->rootCount = (uint32) mark; - - /* - * Free the stack eagerly, risking malloc churn. The alternative would - * require an lrs->entryCount member, maintained by Enter and Leave, and - * tested by the GC in addition to the cx->localRootStack non-null test. - * - * That approach would risk hoarding 264 bytes (net) per context. Right - * now it seems better to give fresh (dirty in CPU write-back cache, and - * the data is no longer needed) memory back to the malloc heap. - */ - if (mark == 0) { - cx->localRootStack = NULL; - JS_free(cx, lrs); - } else if (m == 0) { - lrs->topChunk = lrc->down; - JS_free(cx, lrc); - } -} - -void -js_ForgetLocalRoot(JSContext *cx, jsval v) -{ - JSLocalRootStack *lrs; - unsigned i, j, m, n, mark; - JSLocalRootChunk *lrc, *lrc2; - jsval top; - - lrs = cx->localRootStack; - JS_ASSERT(lrs && lrs->rootCount); - if (!lrs || lrs->rootCount == 0) - return; - - /* Prepare to pop the top-most value from the stack. */ - n = lrs->rootCount - 1; - m = n & JSLRS_CHUNK_MASK; - lrc = lrs->topChunk; - top = lrc->roots[m]; - - /* Be paranoid about calls on an empty scope. */ - mark = lrs->scopeMark; - JS_ASSERT(mark < n); - if (mark >= n) - return; - - /* If v was not the last root pushed in the top scope, find it. */ - if (top != v) { - /* Search downward in case v was recently pushed. */ - i = n; - j = m; - lrc2 = lrc; - while (--i > mark) { - if (j == 0) - lrc2 = lrc2->down; - j = i & JSLRS_CHUNK_MASK; - if (lrc2->roots[j] == v) - break; - } - - /* If we didn't find v in this scope, assert and bail out. */ - JS_ASSERT(i != mark); - if (i == mark) - return; - - /* Swap top and v so common tail code can pop v. */ - lrc2->roots[j] = top; - } - - /* Pop the last value from the stack. */ - lrc->roots[m] = JSVAL_NULL; - lrs->rootCount = n; - if (m == 0) { - JS_ASSERT(n != 0); - JS_ASSERT(lrc != &lrs->firstChunk); - lrs->topChunk = lrc->down; - JS_free(cx, lrc); - } -} - -int -js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v) -{ - unsigned n, m; - JSLocalRootChunk *lrc; - - n = lrs->rootCount; - m = n & JSLRS_CHUNK_MASK; - if (n == 0 || m != 0) { - /* - * At start of first chunk, or not at start of a non-first top chunk. - * Check for lrs->rootCount overflow. - */ - if ((uint32)(n + 1) == 0) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TOO_MANY_LOCAL_ROOTS); - return -1; - } - lrc = lrs->topChunk; - JS_ASSERT(n != 0 || lrc == &lrs->firstChunk); - } else { - /* - * After lrs->firstChunk, trying to index at a power-of-two chunk - * boundary: need a new chunk. - */ - lrc = (JSLocalRootChunk *) JS_malloc(cx, sizeof *lrc); - if (!lrc) - return -1; - lrc->down = lrs->topChunk; - lrs->topChunk = lrc; - } - lrs->rootCount = n + 1; - lrc->roots[m] = v; - return (int) n; -} - -void -js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs) -{ - unsigned n, m, mark; - JSLocalRootChunk *lrc; - - n = lrs->rootCount; - if (n == 0) - return; - - mark = lrs->scopeMark; - lrc = lrs->topChunk; - do { - while (--n > mark) { -#ifdef GC_MARK_DEBUG - char name[22]; - JS_snprintf(name, sizeof name, "", n); -#else - const char *name = NULL; -#endif - m = n & JSLRS_CHUNK_MASK; - JS_ASSERT(JSVAL_IS_GCTHING(lrc->roots[m])); - JS_MarkGCThing(cx, JSVAL_TO_GCTHING(lrc->roots[m]), name, NULL); - if (m == 0) - lrc = lrc->down; - } - m = n & JSLRS_CHUNK_MASK; - mark = JSVAL_TO_INT(lrc->roots[m]); - if (m == 0) - lrc = lrc->down; - } while (n != 0); - JS_ASSERT(!lrc); -} - -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 *); - size_t charArgLength = strlen(charArg); - reportp->messageArgs[i] - = js_InflateString(cx, charArg, &charArgLength); - 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) { - jschar *buffer, *fmt, *out; - const jschar *arg; - int expandedArgs = 0; - size_t expandedLength; - size_t len = strlen (efs->format); - buffer = fmt = js_InflateString (cx, efs->format, &len); - if (!buffer) - goto error; - expandedLength - = len - - (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) { - JS_free (cx, buffer); - goto error; - } - while (*fmt) { - if (*fmt == '{') { - if (isdigit(fmt[1])) { - int d = JS7_UNDEC(fmt[1]); - JS_ASSERT(d < argCount); - arg = reportp->messageArgs[d]; - js_strncpy(out, arg, argLengths[d]); - out += argLengths[d]; - fmt += 3; - expandedArgs++; - continue; - } - } - *out++ = *fmt++; - } - JS_ASSERT(expandedArgs == argCount); - *out = 0; - JS_free (cx, buffer); - *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) { - size_t len; - *messagep = JS_strdup(cx, efs->format); - if (!*messagep) - goto error; - len = strlen(*messagep); - reportp->ucmessage - = js_InflateString(cx, *messagep, &len); - 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 deleted file mode 100644 index ca71c5ad1..000000000 --- a/src/dom/js/jscntxt.h +++ /dev/null @@ -1,803 +0,0 @@ -/* -*- 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" -#include "jsutil.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; - -/* - * Forward declaration for opaque JSRuntime.nativeIteratorStates. - */ -typedef struct JSNativeIteratorState JSNativeIteratorState; - -struct JSRuntime { - /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */ - JSRuntimeState state; - - /* Garbage collector state, used by jsgc.c. */ - JSArenaPool gcArenaPool[GC_NUM_FREELISTS]; - JSGCThing *gcFreeList[GC_NUM_FREELISTS]; - JSDHashTable gcRootsHash; - JSDHashTable *gcLocksHash; - jsrefcount gcKeepAtoms; - uint32 gcBytes; - uint32 gcLastBytes; - uint32 gcMaxBytes; - uint32 gcMaxMallocBytes; - uint32 gcLevel; - uint32 gcNumber; - JSPackedBool gcPoke; - JSPackedBool gcRunning; - JSGCCallback gcCallback; - uint32 gcMallocBytes; - - /* - * API compatibility requires keeping GCX_PRIVATE bytes separate from the - * original GC types' byte tally. Otherwise embeddings that configure a - * good limit for pre-GCX_PRIVATE versions of the engine will see memory - * over-pressure too often, possibly leading to failed last-ditch GCs. - * - * The new XML GC-thing types do add to gcBytes, and they're larger than - * the original GC-thing type size (8 bytes on most architectures). So a - * user who enables E4X may want to increase the maxbytes value passed to - * JS_NewRuntime. TODO: Note this in the API docs. - */ - uint32 gcPrivateBytes; - -#if JS_HAS_XML_SUPPORT - /* Lists of JSXML private data structures to be finalized. */ - JSXMLNamespace *gcDoomedNamespaces; - JSXMLQName *gcDoomedQNames; - JSXML *gcDoomedXML; -#endif -#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; - - /* Optional hook to find principals for an object in this runtime. */ - JSObjectPrincipalsFinder findObjectPrincipals; - - /* Shared scope property tree, and allocator for its nodes. */ - JSDHashTable propertyTreeHash; - JSScopeProperty *propertyFreeList; - JSArenaPool propertyArenaPool; - - /* Script filename table. */ - struct JSHashTable *scriptFilenameTable; - JSCList scriptFilenamePrefixes; -#ifdef JS_THREADSAFE - PRLock *scriptFilenameTableLock; -#endif - - /* Number localization, used by jsnum.c */ - const char *thousandsSeparator; - const char *decimalSeparator; - const char *numGrouping; - - /* - * Weak references to lazily-created, well-known XML singletons. - * - * NB: Singleton objects must be carefully disconnected from the rest of - * the object graph usually associated with a JSContext's global object, - * including the set of standard class objects. See jsxml.c for details. - */ - JSObject *anynameObject; - JSObject *functionNamespaceObject; - - /* - * A helper list for the GC, so it can mark native iterator states. See - * js_MarkNativeIteratorStates for details. - */ - JSNativeIteratorState *nativeIteratorStates; - -#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 */ - -typedef struct JSLocalRootChunk JSLocalRootChunk; - -#define JSLRS_CHUNK_SHIFT 8 -#define JSLRS_CHUNK_SIZE JS_BIT(JSLRS_CHUNK_SHIFT) -#define JSLRS_CHUNK_MASK JS_BITMASK(JSLRS_CHUNK_SHIFT) - -struct JSLocalRootChunk { - jsval roots[JSLRS_CHUNK_SIZE]; - JSLocalRootChunk *down; -}; - -typedef struct JSLocalRootStack { - uint32 scopeMark; - uint32 rootCount; - JSLocalRootChunk *topChunk; - JSLocalRootChunk firstChunk; -} JSLocalRootStack; - -#define JSLRS_NULL_MARK ((uint32) -1) - -typedef struct JSTempValueRooter JSTempValueRooter; -typedef void -(* JS_DLL_CALLBACK JSTempValueMarker)(JSContext *cx, JSTempValueRooter *tvr); - -typedef union JSTempValueUnion { - jsval value; - JSObject *object; - JSTempValueMarker marker; - jsval *array; -} JSTempValueUnion; - -/* - * Context-linked stack of temporary GC roots. - * - * If count is -1, then u.value contains the single value to root. - * If count is -2, then u.marker holds a mark hook that is executed to mark - * the values. - * If count >= 0, then u.array points to a stack-allocated vector of jsvals. - * - * To root a single GC-thing pointer, which need not be tagged and stored as a - * jsval, use JS_PUSH_SINGLE_TEMP_ROOT. The (jsval)(val) cast works because a - * GC-thing is aligned on a 0 mod 8 boundary, and object has the 0 jsval tag. - * So any GC-thing may be tagged as if it were an object and untagged, if it's - * then used only as an opaque pointer until discriminated by other means than - * tag bits (this is how the GC mark function uses its |thing| parameter -- it - * consults GC-thing flags stored separately from the thing to decide the type - * of thing). - * - * Alternatively, if a single pointer to rooted JSObject * is required, use - * JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr). Then &tvr.u.object gives the - * necessary pointer, which puns tvr.u.value safely because object tag bits - * are all zeroes. - * - * If you need to protect a result value that flows out of a C function across - * several layers of other functions, use the js_LeaveLocalRootScopeWithResult - * internal API (see further below) instead. - */ -struct JSTempValueRooter { - JSTempValueRooter *down; - ptrdiff_t count; - JSTempValueUnion u; -}; - -#define JS_PUSH_TEMP_ROOT_COMMON(cx,tvr) \ - JS_BEGIN_MACRO \ - JS_ASSERT((cx)->tempValueRooters != (tvr)); \ - (tvr)->down = (cx)->tempValueRooters; \ - (cx)->tempValueRooters = (tvr); \ - JS_END_MACRO - -#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr) \ - JS_BEGIN_MACRO \ - JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \ - (tvr)->count = -1; \ - (tvr)->u.value = (val); \ - JS_END_MACRO - -#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr) \ - JS_BEGIN_MACRO \ - JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \ - JS_ASSERT((ptrdiff_t)(cnt) >= 0); \ - (tvr)->count = (ptrdiff_t)(cnt); \ - (tvr)->u.array = (arr); \ - JS_END_MACRO - -#define JS_PUSH_TEMP_ROOT_MARKER(cx,marker_,tvr) \ - JS_BEGIN_MACRO \ - JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \ - (tvr)->count = -2; \ - (tvr)->u.marker = (marker_); \ - JS_END_MACRO - -#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr) \ - JS_BEGIN_MACRO \ - JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \ - (tvr)->count = -1; \ - (tvr)->u.object = (obj); \ - JS_END_MACRO - -#define JS_POP_TEMP_ROOT(cx,tvr) \ - JS_BEGIN_MACRO \ - JS_ASSERT((cx)->tempValueRooters == (tvr)); \ - (cx)->tempValueRooters = (tvr)->down; \ - JS_END_MACRO - -#define JS_TEMP_ROOT_EVAL(cx,cnt,val,expr) \ - JS_BEGIN_MACRO \ - JSTempValueRooter tvr; \ - JS_PUSH_TEMP_ROOT(cx, cnt, val, &tvr); \ - (expr); \ - JS_POP_TEMP_ROOT(cx, &tvr); \ - JS_END_MACRO - -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. */ - uint16 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; - - /* Root for the result of the most recent js_InternalInvoke call. */ - jsval lastInternalResult; - - /* 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 - -#if JS_HAS_XML_SUPPORT - /* - * Bit-set formed from binary exponentials of the XML_* tiny-ids defined - * for boolean settings in jsxml.c, plus an XSF_CACHE_VALID bit. Together - * these act as a cache of the boolean XML.ignore* and XML.prettyPrinting - * property values associated with this context's global object. - */ - uint8 xmlSettingFlags; -#endif - - /* - * True if creating an exception object, to prevent runaway recursion. - * NB: creatingException packs with rval2set, #if JS_HAS_LVALUE_RETURN; - * with xmlSettingFlags, #if JS_HAS_XML_SUPPORT; 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 stack of heap-allocated scoped local GC roots. */ - JSLocalRootStack *localRootStack; - - /* Stack of thread-stack-allocated temporary GC roots. */ - JSTempValueRooter *tempValueRooters; -}; - -#ifdef __cplusplus -/* FIXME(bug 332648): Move this into a public header. */ -class JSAutoTempValueRooter -{ - public: - JSAutoTempValueRooter(JSContext *cx, size_t len, jsval *vec) - : mContext(cx) { - JS_PUSH_TEMP_ROOT(mContext, len, vec, &mTvr); - } - JSAutoTempValueRooter(JSContext *cx, jsval v) - : mContext(cx) { - JS_PUSH_SINGLE_TEMP_ROOT(mContext, v, &mTvr); - } - - virtual ~JSAutoTempValueRooter() { - JS_POP_TEMP_ROOT(mContext, &mTvr); - } - - private: - static void *operator new(size_t) { return 0; } - static void operator delete(void *, size_t) { } - - JSContext *mContext; - JSTempValueRooter mTvr; -}; -#endif - -/* - * Slightly more readable macros for testing per-context option settings (also - * to hide bitset implementation detail). - * - * JSOPTION_XML must be handled specially in order to propagate from compile- - * to run-time (from cx->options to script->version/cx->version). To do that, - * we copy JSOPTION_XML from cx->options into cx->version as JSVERSION_HAS_XML - * whenever options are set, and preserve this XML flag across version number - * changes done via the JS_SetVersion API. - * - * But when executing a script or scripted function, the interpreter changes - * cx->version, including the XML flag, to script->version. Thus JSOPTION_XML - * is a compile-time option that causes a run-time version change during each - * activation of the compiled script. That version change has the effect of - * changing JS_HAS_XML_OPTION, so that any compiling done via eval enables XML - * support. If an XML-enabled script or function calls a non-XML function, - * the flag bit will be cleared during the callee's activation. - * - * Note that JS_SetVersion API calls never pass JSVERSION_HAS_XML or'd into - * that API's version parameter. - * - * Note also that script->version must contain this XML option flag in order - * for XDR'ed scripts to serialize and deserialize with that option preserved - * for detection at run-time. We can't copy other compile-time options into - * script->version because that would break backward compatibility (certain - * other options, e.g. JSOPTION_VAROBJFIX, are analogous to JSOPTION_XML). - */ -#define JS_HAS_OPTION(cx,option) (((cx)->options & (option)) != 0) -#define JS_HAS_STRICT_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_STRICT) -#define JS_HAS_WERROR_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_WERROR) -#define JS_HAS_COMPILE_N_GO_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_COMPILE_N_GO) -#define JS_HAS_ATLINE_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_ATLINE) - -#define JSVERSION_MASK 0x0FFF /* see JSVersion in jspubtd.h */ -#define JSVERSION_HAS_XML 0x1000 /* flag induced by XML option */ - -#define JSVERSION_NUMBER(cx) ((cx)->version & JSVERSION_MASK) -#define JS_HAS_XML_OPTION(cx) ((cx)->version & JSVERSION_HAS_XML || \ - JSVERSION_NUMBER(cx) >= JSVERSION_1_6) - -#define JS_HAS_NATIVE_BRANCH_CALLBACK_OPTION(cx) \ - JS_HAS_OPTION(cx, JSOPTION_NATIVE_BRANCH_CALLBACK) - -/* - * Wrappers for the JSVERSION_IS_* macros from jspubtd.h taking JSContext *cx - * and masking off the XML flag and any other high order bits. - */ -#define JS_VERSION_IS_ECMA(cx) JSVERSION_IS_ECMA(JSVERSION_NUMBER(cx)) -#define JS_VERSION_IS_1_2(cx) (JSVERSION_NUMBER(cx) == JSVERSION_1_2) - -/* - * Common subroutine of JS_SetVersion and js_SetVersion, to update per-context - * data that depends on version. - */ -extern void -js_OnVersionChange(JSContext *cx); - -/* - * Unlike the JS_SetVersion API, this function stores JSVERSION_HAS_XML and - * any future non-version-number flags induced by compiler options. - */ -extern void -js_SetVersion(JSContext *cx, JSVersion version); - -/* - * Create and destroy functions for JSContext, which is manually allocated - * and exclusively owned. - */ -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); - -/* - * JSClass.resolve and watchpoint recursion damping machinery. - */ -extern JSBool -js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, - JSResolvingEntry **entryp); - -extern void -js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, - JSResolvingEntry *entry, uint32 generation); - -/* - * Local root set management. - */ -extern JSBool -js_EnterLocalRootScope(JSContext *cx); - -extern void -js_LeaveLocalRootScope(JSContext *cx); - -extern void -js_ForgetLocalRoot(JSContext *cx, jsval v); - -extern int -js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v); - -extern void -js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs); - -/* - * 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 deleted file mode 100644 index 6ba036a5e..000000000 --- a/src/dom/js/jscompat.h +++ /dev/null @@ -1,57 +0,0 @@ -/* ***** 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 deleted file mode 100644 index 5902499f9..000000000 --- a/src/dom/js/jsconfig.h +++ /dev/null @@ -1,563 +0,0 @@ -/* -*- 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 160 -#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 1.6 - * ^ ^ - * | | - * 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 */ -#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ - -#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 */ -#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ - -#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 */ -#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ - -#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 */ -#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ - -#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 */ -#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ - -#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 */ -#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ - -#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 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 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 */ -#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ - -#elif JS_VERSION == 160 - -#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 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 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 */ -#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */ -#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */ - -#else - -#error "unknown JS_VERSION" - -#endif diff --git a/src/dom/js/jscpucfg.c b/src/dom/js/jscpucfg.c deleted file mode 100644 index e02f33615..000000000 --- a/src/dom/js/jscpucfg.c +++ /dev/null @@ -1,375 +0,0 @@ -/* -*- 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 - * - * 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 -#include - -#ifdef CROSS_COMPILE -#include -#define INT64 PRInt64 -#else - -/************************************************************************/ - -/* Generate cpucfg.h */ - -#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 /* CROSS_COMPILE */ - -#ifdef __GNUC__ -#define NS_NEVER_INLINE __attribute__((noinline)) -#else -#define NS_NEVER_INLINE -#endif - -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 NS_NEVER_INLINE 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 deleted file mode 100644 index 7b8b2add4..000000000 --- a/src/dom/js/jscpucfg.h +++ /dev/null @@ -1,159 +0,0 @@ -/* -*- 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" - -#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE) - -#ifdef __WATCOMC__ -#define HAVE_VA_LIST_AS_ARRAY -#endif - -#if defined(_WIN32) || defined(XP_OS2) || defined(WINCE) -#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 || WINCE*/ - -#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_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 deleted file mode 100644 index a76502c38..000000000 --- a/src/dom/js/jsdate.c +++ /dev/null @@ -1,2386 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include -#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; -} - -#define MakeTime(hour, min, sec, ms) \ -((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms)) - -static jsdouble -MakeDay(jsdouble year, jsdouble month, jsdouble date) -{ - 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); - - return yearday + monthday + date - 1; -} - -#define MakeDate(day, time) ((day) * msPerDay + (time)) - -/* - * Years and leap years on which Jan 1 is a Sunday, Monday, etc. - * - * yearStartingWith[0][i] is an example non-leap year where - * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. - * - * yearStartingWith[1][i] is an example leap year where - * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. - */ -static jsint yearStartingWith[2][7] = { - {1978, 1973, 1974, 1975, 1981, 1971, 1977}, - {1984, 1996, 1980, 1992, 1976, 1988, 1972} -}; - -/* - * Find a year for which any given date will fall on the same weekday. - * - * This function should be used with caution when used other than - * for determining DST; it hasn't been proven not to produce an - * incorrect year for times near year boundaries. - */ -static jsint -EquivalentYearForDST(jsint year) { - jsint day; - JSBool isLeapYear; - - day = (jsint) DayFromYear(year) + 4; - day = day % 7; - if (day < 0) - day += 7; - - isLeapYear = (DaysInYear(year) == 366); - - return yearStartingWith[isLeapYear][day]; -} - -/* 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; - - /* - * If earlier than 1970 or after 2038, potentially beyond the ken of - * many OSes, map it to an equivalent year before asking. - */ - if (t < 0.0 || t > 2145916800000.0) { - jsint year; - jsdouble day; - - year = EquivalentYearForDST(YearFromTime(t)); - day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); - t = MakeDate(day, TimeWithinDay(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 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; - int temp; - JSBool seenmonthname = 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 (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) { - if (c <= ' ' || c == ',' || c == '/' || i >= limit) - year = 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 == '/') { - /* until it is determined that mon is the actual - month, keep it as 1-based rather than 0-based */ - if (mon < 0) - mon = /*byte*/ n; - else if (mday < 0) - mday = /*byte*/ n; - else - goto syntax; - } else if (i < limit && c != ',' && 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 (prevc == ':' && min >= 0 && sec < 0) { - sec = /*byte*/ n; - } else if (mon < 0) { - mon = /*byte*/n; - } else if (mon >= 0 && mday < 0) { - mday = /*byte*/ n; - } else if (mon >= 0 && mday >= 0 && year < 0) { - year = 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! */ - /* Adjust mon to be 1-based until the final values - for mon, mday and year are adjusted below */ - if (seenmonthname) { - goto syntax; - } - seenmonthname = JS_TRUE; - temp = /*byte*/ (action - 2) + 1; - - if (mon < 0) { - mon = temp; - } else if (mday < 0) { - mday = mon; - mon = temp; - } else if (year < 0) { - year = mon; - mon = temp; - } else { - goto syntax; - } - } else { - tzoffset = action - 10000; - } - } - break; - } - if (k < 0) - goto syntax; - prevc = 0; - } - } - if (year < 0 || mon < 0 || mday < 0) - goto syntax; - /* - Case 1. The input string contains an English month name. - The form of the string can be month f l, or f month l, or - f l month which each evaluate to the same date. - If f and l are both greater than or equal to 70, or - both less than 70, the date is invalid. - The year is taken to be the greater of the values f, l. - If the year is greater than or equal to 70 and less than 100, - it is considered to be the number of years after 1900. - Case 2. The input string is of the form "f/m/l" where f, m and l are - integers, e.g. 7/16/45. - Adjust the mon, mday and year values to achieve 100% MSIE - compatibility. - a. If 0 <= f < 70, f/m/l is interpreted as month/day/year. - i. If year < 100, it is the number of years after 1900 - ii. If year >= 100, it is the number of years after 0. - b. If 70 <= f < 100 - i. If m < 70, f/m/l is interpreted as - year/month/day where year is the number of years after - 1900. - ii. If m >= 70, the date is invalid. - c. If f >= 100 - i. If m < 70, f/m/l is interpreted as - year/month/day where year is the number of years after 0. - ii. If m >= 70, the date is invalid. - */ - if (seenmonthname) { - if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) { - goto syntax; - } - if (mday > year) { - temp = year; - year = mday; - mday = temp; - } - if (year >= 70 && year < 100) { - year += 1900; - } - } else if (mon < 70) { /* (a) month/day/year */ - if (year < 100) { - year += 1900; - } - } else if (mon < 100) { /* (b) year/month/day */ - if (mday < 70) { - temp = year; - year = mon + 1900; - mon = mday; - mday = temp; - } else { - goto syntax; - } - } else { /* (c) year/month/day */ - if (mday < 70) { - temp = year; - year = mon; - mon = mday; - mday = temp; - } else { - goto syntax; - } - } - mon -= 1; /* convert month to 0-based */ - 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 *date; - jsdouble result; - JSVersion version; - - 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... - */ - version = cx->version & JSVERSION_MASK; - if (version == JSVERSION_1_0 || - version == JSVERSION_1_1 || - 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)); - } - - } - - if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) - return cx->localeCallbacks->localeToUnicode(cx, buf, rval); - - 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_toLocaleFormat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSString *fmt; - - if (argc == 0) - return date_toLocaleString(cx, obj, argc, argv, rval); - - fmt = JS_ValueToString(cx, argv[0]); - if (!fmt) - return JS_FALSE; - - return date_toLocaleHelper(cx, obj, argc, argv, rval, - JS_GetStringBytes(fmt)); -} - -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 -#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 }, - {"toLocaleFormat", date_toLocaleFormat, 1,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, 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 deleted file mode 100644 index 343314fab..000000000 --- a/src/dom/js/jsdate.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- 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 deleted file mode 100644 index cddbd4808..000000000 --- a/src/dom/js/jsdbgapi.c +++ /dev/null @@ -1,1405 +0,0 @@ -/* -*- 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 -#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(JSContext *cx) -{ - JSRuntime *rt; - JSWatchPoint *wp; - - rt = cx->runtime; - for (wp = (JSWatchPoint *)rt->watchPointList.next; - wp != (JSWatchPoint *)&rt->watchPointList; - wp = (JSWatchPoint *)wp->links.next) { - MARK_SCOPE_PROPERTY(wp->sprop); - if (wp->sprop->attrs & JSPROP_SETTER) - JS_MarkGCThing(cx, wp->setter, "wp->setter", NULL); - } -} - -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 propid, 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); - propid = ID_TO_VALUE(sprop->id); - userid = (sprop->flags & SPROP_HAS_SHORTID) - ? INT_TO_JSVAL(sprop->shortid) - : propid; - scope = OBJ_SCOPE(obj); - JS_UNLOCK_OBJ(cx, obj); - HoldWatchPoint(wp); - ok = wp->handler(cx, obj, propid, - 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 *closure; - JSClass *clasp; - JSFunction *fun; - JSScript *script; - uintN nslots; - jsval smallv[5]; - jsval *argv; - JSStackFrame frame; - - closure = (JSObject *) wp->closure; - clasp = OBJ_GET_CLASS(cx, closure); - if (clasp == &js_FunctionClass) { - fun = (JSFunction *) JS_GetPrivate(cx, closure); - script = FUN_SCRIPT(fun); - } else if (clasp == &js_ScriptClass) { - fun = NULL; - script = (JSScript *) JS_GetPrivate(cx, closure); - } else { - fun = NULL; - script = NULL; - } - - nslots = 2; - if (fun) { - nslots += fun->nargs; - if (FUN_NATIVE(fun)) - nslots += fun->extra; - } - - if (nslots <= sizeof (smallv) / sizeof (smallv[0])) { - argv = smallv; - } else { - argv = JS_malloc(cx, nslots * sizeof(jsval)); - if (!argv) { - DropWatchPoint(cx, wp); - return JS_FALSE; - } - } - - argv[0] = OBJECT_TO_JSVAL(closure); - argv[1] = JSVAL_NULL; - memset(argv + 2, 0, (nslots - 2) * sizeof(jsval)); - - memset(&frame, 0, sizeof(frame)); - frame.script = script; - if (script) - frame.pc = script->code; - frame.fun = fun; - frame.argv = argv + 2; - frame.down = cx->fp; - frame.scopeChain = OBJ_GET_PARENT(cx, closure); - - 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; - if (argv != smallv) - JS_free(cx, argv); - } - 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]); - JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass); - 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 (JSID_IS_ATOM(id)) { - atom = JSID_TO_ATOM(id); - } else if (JSID_IS_INT(id)) { - atom = js_AtomizeInt(cx, JSID_TO_INT(id), 0); - if (!atom) - return NULL; - } else { - atom = 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; - JSProperty *prop; - JSScopeProperty *sprop; - JSRuntime *rt; - JSBool ok; - 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 = INT_JSVAL_TO_JSID(id); - atom = NULL; - } else { - atom = js_ValueToStringAtom(cx, id); - if (!atom) - return JS_FALSE; - propid = ATOM_TO_JSID(atom); - } - - if (!js_LookupProperty(cx, obj, propid, &pobj, &prop)) - return JS_FALSE; - sprop = (JSScopeProperty *) prop; - 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, - &prop)) { - return JS_FALSE; - } - sprop = (JSScopeProperty *) prop; - } - } else if (pobj != obj) { - /* Clone the prototype property so we can watch the right object. */ - jsval value; - JSPropertyOp getter, setter; - uintN attrs, flags; - intN shortid; - - 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; - flags = sprop->flags; - shortid = sprop->shortid; - } else { - if (!OBJ_GET_PROPERTY(cx, pobj, id, &value) || - !OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs)) { - OBJ_DROP_PROPERTY(cx, pobj, prop); - return JS_FALSE; - } - getter = setter = NULL; - flags = 0; - shortid = 0; - } - OBJ_DROP_PROPERTY(cx, pobj, prop); - - /* Recall that obj is native, whether or not pobj is native. */ - if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter, - attrs, flags, shortid, &prop)) { - return JS_FALSE; - } - sprop = (JSScopeProperty *) prop; - } - - /* - * At this point, prop/sprop exists in obj, obj is locked, and we must - * OBJ_DROP_PROPERTY(cx, obj, prop) before returning. - */ - ok = JS_TRUE; - wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid); - if (!wp) { - watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter); - if (!watcher) { - ok = JS_FALSE; - goto out; - } - - wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp); - if (!wp) { - ok = JS_FALSE; - goto out; - } - wp->handler = NULL; - wp->closure = NULL; - ok = js_AddRoot(cx, &wp->closure, "wp->closure"); - if (!ok) { - JS_free(cx, wp); - goto out; - } - wp->object = obj; - JS_ASSERT(sprop->setter != js_watch_set || pobj != obj); - wp->setter = sprop->setter; - wp->nrefs = 1; - - /* XXXbe nest in obj lock here */ - sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs, - sprop->getter, watcher); - if (!sprop) { - /* Self-link wp->links so DropWatchPoint can JS_REMOVE_LINK it. */ - JS_INIT_CLIST(&wp->links); - DropWatchPoint(cx, wp); - ok = JS_FALSE; - goto out; - } - wp->sprop = sprop; - - /* Now that wp is fully initialized, append it to rt's wp list. */ - JS_APPEND_LINK(&wp->links, &rt->watchPointList); - } - wp->handler = handler; - wp->closure = closure; - -out: - OBJ_DROP_PROPERTY(cx, obj, prop); - return ok; -} - -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(fun); -} - -JS_PUBLIC_API(JSNative) -JS_GetFunctionNative(JSContext *cx, JSFunction *fun) -{ - return FUN_NATIVE(fun); -} - -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) { - JSRuntime *rt = cx->runtime; - - if (rt->findObjectPrincipals) { - JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]); - - if (fp->fun->object != callee) - return rt->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) -{ - JSRuntime *rt; - JSObject *callee; - JSPrincipals *principals, *callerPrincipals; - - rt = cx->runtime; - if (rt->findObjectPrincipals) { - callee = JSVAL_TO_OBJECT(fp->argv[-2]); - principals = rt->findObjectPrincipals(cx, callee); - } else { - principals = NULL; - } - if (!caller) - return principals; - callerPrincipals = JS_StackFramePrincipals(cx, caller); - return (callerPrincipals && principals && - callerPrincipals->subsume(callerPrincipals, principals)) - ? principals - : callerPrincipals; -} - -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(JSObject *) -JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp) -{ - return fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL; -} - -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 & JSVERSION_MASK; -} - -/***************************************************************************/ - -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, options; - 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; - options = cx->options; - cx->options = options | JSOPTION_COMPILE_N_GO; - script = JS_CompileUCScriptForPrincipals(cx, fp->scopeChain, - JS_StackFramePrincipals(cx, fp), - bytes, length, filename, lineno); - fp->flags = flags; - cx->options = options; - 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 nbytes, - const char *filename, uintN lineno, - jsval *rval) -{ - size_t length = nbytes; - 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->interpreted) - nbytes += JS_GetScriptTotalSize(cx, fun->u.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; -} - -JS_PUBLIC_API(uint32) -JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp) -{ - if (!fp) - fp = cx->fp; - while (fp) { - if (fp->script) { - return JS_GetScriptFilenameFlags(fp->script); - } - fp = fp->down; - } - return 0; - } - -JS_PUBLIC_API(uint32) -JS_GetScriptFilenameFlags(JSScript *script) -{ - JS_ASSERT(script); - if (!script->filename) - return JSFILENAME_NULL; - return js_GetScriptFilenameFlags(script->filename); -} - -JS_PUBLIC_API(JSBool) -JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags) -{ - if (!js_SaveScriptFilenameRT(rt, prefix, flags)) - return JS_FALSE; - return JS_TRUE; -} - -JS_PUBLIC_API(JSBool) -JS_IsSystemObject(JSContext *cx, JSObject *obj) -{ - return (*js_GetGCThingFlags(obj) & GCF_SYSTEM) != 0; -} - -JS_PUBLIC_API(void) -JS_FlagSystemObject(JSContext *cx, JSObject *obj) -{ - uint8 *flagp; - - flagp = js_GetGCThingFlags(obj); - *flagp |= GCF_SYSTEM; -} diff --git a/src/dom/js/jsdbgapi.h b/src/dom/js/jsdbgapi.h deleted file mode 100644 index d1b13d9d4..000000000 --- a/src/dom/js/jsdbgapi.h +++ /dev/null @@ -1,406 +0,0 @@ -/* -*- 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(JSContext *cx); - -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(JSNative) -JS_GetFunctionNative(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); - -/* - * This API is like JS_StackFramePrincipals(cx, caller), except that if - * cx->runtime->findObjectPrincipals is non-null, it returns the weaker of - * the caller's principals and the object principals of fp's callee function - * object (fp->argv[-2]), which is eval, Function, or a similar eval-like - * method. The caller parameter should be 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); - -/** - * Return fp's callee function object (fp->argv[-2]) if it has one. - */ -extern JS_PUBLIC_API(JSObject *) -JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp); - -/************************************************************************/ - -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); - -/* - * Get the top-most running script on cx starting from fp, or from the top of - * cx's frame stack if fp is null, and return its script filename flags. If - * the script has a null filename member, return JSFILENAME_NULL. - */ -extern JS_PUBLIC_API(uint32) -JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp); - -/* - * Get the script filename flags for the script. If the script - * doesn't have a filename, return JSFILENAME_NULL. - */ -extern JS_PUBLIC_API(uint32) -JS_GetScriptFilenameFlags(JSScript *script); - -/* - * Associate flags with a script filename prefix in rt, so that any subsequent - * script compilation will inherit those flags if the script's filename is the - * same as prefix, or if prefix is a substring of the script's filename. - * - * The API defines only one flag bit, JSFILENAME_SYSTEM, leaving the remaining - * 31 bits up to the API client to define. The union of all 32 bits must not - * be a legal combination, however, in order to preserve JSFILENAME_NULL as a - * unique value. API clients may depend on JSFILENAME_SYSTEM being a set bit - * in JSFILENAME_NULL -- a script with a null filename member is presumed to - * be a "system" script. - */ -extern JS_PUBLIC_API(JSBool) -JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags); - -#define JSFILENAME_NULL 0xffffffff /* null script filename */ -#define JSFILENAME_SYSTEM 0x00000001 /* "system" script, see below */ - -/* - * Return true if obj is a "system" object, that is, one flagged by a prior - * call to JS_FlagSystemObject(cx, obj). What "system" means is up to the API - * client, but it can be used to coordinate access control policies based on - * script filenames and their prefixes, using JS_FlagScriptFilenamePrefix and - * JS_GetTopScriptFilenameFlags. - */ -extern JS_PUBLIC_API(JSBool) -JS_IsSystemObject(JSContext *cx, JSObject *obj); - -/* - * Flag obj as a "system" object. The API client can flag system objects to - * optimize access control checks. The engine stores but does not interpret - * the per-object flag set by this call. - */ -extern JS_PUBLIC_API(void) -JS_FlagSystemObject(JSContext *cx, JSObject *obj); - -JS_END_EXTERN_C - -#endif /* jsdbgapi_h___ */ diff --git a/src/dom/js/jsdhash.c b/src/dom/js/jsdhash.c deleted file mode 100644 index cd3006685..000000000 --- a/src/dom/js/jsdhash.c +++ /dev/null @@ -1,767 +0,0 @@ -/* -*- 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 (Original Author) - * Chris Waterson - * - * 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 -#include -#include -#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)(unsigned long)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; - - JS_CEILING_LOG2(log2, 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 * JS_DHASH_FASTCALL -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_DHASH_FASTCALL -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, ceiling; - 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; - - JS_CEILING_LOG2(ceiling, capacity); - ceiling -= JS_DHASH_BITS - table->hashShift; - - (void) ChangeTable(table, ceiling); - } - return i; -} - -#ifdef JS_DHASHMETER -#include - -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 deleted file mode 100644 index 6beecadd1..000000000 --- a/src/dom/js/jsdhash.h +++ /dev/null @@ -1,579 +0,0 @@ -/* -*- 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 (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 - -#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2) -#define JS_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall)) -#else -#define JS_DHASH_FASTCALL -#endif - -#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. - */ -extern 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_DHASH_FASTCALL -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 - -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 deleted file mode 100644 index ff6731bfa..000000000 --- a/src/dom/js/jsdtoa.c +++ /dev/null @@ -1,3126 +0,0 @@ -/* -*- 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" -#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 ab, 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 = 0; - - 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 = 0; -#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; - - *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; - return sign ? -rv : rv; - -nomem: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); - *err = JS_DTOA_ENOMEM; - return 0; -} - - -/* 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<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; - - 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); */ - return JS_FALSE; - } - strcpy(buf, s); - if (rve) { - *rve = buf[3] ? buf + 8 : buf + 3; - JS_ASSERT(**rve == '\0'); - } - return JS_TRUE; - } - - 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); */ - return JS_FALSE; - } - 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); - return JS_TRUE; - } - - 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); - return JS_FALSE; - } - 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; - } - - /* Use true number of digits to limit looping. */ - for(i = 1; i<=k+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; - } - d *= 10.; - } - 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++ = (char)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; - return JS_TRUE; - -nomem: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); - } - Bfree(b); - return JS_FALSE; -} - - -/* 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< 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 deleted file mode 100644 index 409f45454..000000000 --- a/src/dom/js/jsdtoa.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- 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 . - */ -/* 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 digits after the decimal point; exponential if number is large */ - DTOSTR_EXPONENTIAL, /* Always exponential format; significant digits */ - DTOSTR_PRECISION /* Either fixed or exponential format; 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 deleted file mode 100644 index c7e32f200..000000000 --- a/src/dom/js/jsemit.c +++ /dev/null @@ -1,5399 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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 -#endif -#include -#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 "jsregexp.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; - ATOM_LIST_INIT(&cg->constList); - 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; - JS_ASSERT(cg->stackDepth >= 0); - if (cg->stackDepth < 0) { - char numBuf[12]; - JS_snprintf(numBuf, sizeof numBuf, "%d", target); - JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, - 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"; -const char js_script_str[] = "script"; - -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 js_script_str; - 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.cmcrossroads.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_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) + cg->spanDepTodo; - 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 */ - } - - JS_ASSERT(len > 0); - 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_SPAN(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_SPAN(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; - } - } - } - cg->main.lastNoteOffset += growth; - - /* - * 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_SPAN(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; - cg->spanDepTodo = CG_OFFSET(cg); - return JS_TRUE; -} - -static JSBool -EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off) -{ - JSBool extend; - ptrdiff_t jmp; - jsbytecode *pc; - - extend = off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off; - if (extend && !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 && (extend || 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. - */ -static ptrdiff_t -EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) -{ - ptrdiff_t offset, delta; - - offset = CG_OFFSET(cg); - delta = offset - *lastp; - *lastp = offset; - JS_ASSERT(delta > 0); - return EmitJump(cx, cg, op, delta); -} - -/* 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; - jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmt->gosub); - 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 [exception or hole, retsub pc-index] pair 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_POP2) < 0) - return JS_FALSE; - break; - - default:; - } - } - - cg->stackDepth = depth; - return JS_TRUE; -} - -static ptrdiff_t -EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, - ptrdiff_t *lastp, JSAtomListElement *label, JSSrcNoteType noteType) -{ - intN index; - - 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; - } - - return EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp); -} - -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; -} - -JSBool -js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - JSParseNode *pn) -{ - jsdouble dval; - jsint ival; - JSAtom *valueAtom; - JSAtomListElement *ale; - - /* XXX just do numbers for now */ - if (pn->pn_type == TOK_NUMBER) { - dval = pn->pn_dval; - valueAtom = (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) - ? js_AtomizeInt(cx, ival, 0) - : js_AtomizeDouble(cx, dval, 0); - if (!valueAtom) - return JS_FALSE; - ale = js_IndexAtom(cx, atom, &cg->constList); - if (!ale) - return JS_FALSE; - ALE_SET_VALUE(ale, ATOM_KEY(valueAtom)); - } - return JS_TRUE; -} - -JSBool -js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - jsval *vp) -{ - JSBool ok; - JSStackFrame *fp; - JSAtomListElement *ale; - JSObject *obj, *pobj; - JSProperty *prop; - uintN attrs; - - /* - * fp chases cg down the stack, but only until we reach the outermost cg. - * This enables propagating consts from top-level into switch cases in a - * function compiled along with the top-level script. All stack frames - * with matching code generators should be flagged with JSFRAME_COMPILING; - * we check sanity here. - */ - *vp = JSVAL_VOID; - ok = JS_TRUE; - fp = cx->fp; - do { - JS_ASSERT(fp->flags & JSFRAME_COMPILING); - - obj = fp->varobj; - if (obj == fp->scopeChain && - !js_InWithStatement(&cg->treeContext) && - !js_InCatchBlock(&cg->treeContext, atom)) { - ATOM_LIST_SEARCH(ale, &cg->constList, atom); - if (ale) { - *vp = ALE_VALUE(ale); - return JS_TRUE; - } - - /* - * Try looking in the variable object for a direct property that - * is readonly and permanent. We know such a property can't be - * shadowed by another property on obj's prototype chain, or a - * with object or catch variable; nor can prop's value be changed, - * nor can prop be deleted. - */ - prop = NULL; - if (OBJ_IS_NATIVE(obj)) { - ok = js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), - &pobj, &prop); - if (!ok) - break; - if (prop) { - /* - * Any hidden property must be a formal arg or local var, - * which will shadow a global const of the same name. - */ - OBJ_DROP_PROPERTY(cx, pobj, prop); - break; - } - } - - ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop); - if (ok) { - if (pobj == obj && - (fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO))) { - /* - * We're compiling code that will be executed immediately, - * not re-executed against a different scope chain and/or - * variable object. Therefore we can get constant values - * from our variable object here. - */ - ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, - &attrs); - if (ok && !(~attrs & (JSPROP_READONLY | JSPROP_PERMANENT))) - ok = OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp); - } - if (prop) - OBJ_DROP_PROPERTY(cx, pobj, prop); - } - if (!ok || prop) - break; - } - fp = fp->down; - } while ((cg = cg->parent) != NULL); - return ok; -} - -/* - * Allocate an index invariant for all activations of the code being compiled - * in cg, that can be used to store and fetch a reference to a cloned RegExp - * object that shares the same JSRegExp private data created for the object - * literal in pn->pn_atom. We need clones to hold lastIndex and other direct - * properties that should not be shared among threads sharing a precompiled - * function or script. - * - * If the code being compiled is function code, allocate a reserved slot in - * the cloned function object that shares its precompiled script with other - * cloned function objects and with the compiler-created clone-parent. There - * are fun->nregexps such reserved slots in each function object cloned from - * fun->object. NB: during compilation, funobj slots must never be allocated, - * because js_AllocSlot could hand out one of the slots that should be given - * to a regexp clone. - * - * If the code being compiled is global code, reserve the fp->vars slot at - * ALE_INDEX(ale), by ensuring that cg->treeContext.numGlobalVars is at least - * one more than this index. For global code, fp->vars is parallel to the - * global script->atomMap.vector array, but possibly shorter for the common - * case (where var declarations and regexp literals cluster toward the front - * of the script or function body). - * - * Global variable name literals in script->atomMap have fast-global slot - * numbers (stored as int-tagged jsvals) in the corresponding fp->vars array - * element. The atomIndex for a regexp object literal thus also addresses an - * fp->vars element that is not used by any optimized global variable, so we - * use that GC-scanned element to keep the regexp object clone alive, as well - * as to lazily create and find it at run-time for the JSOP_REGEXP bytecode. - * - * In no case can cx->fp->varobj be a Call object here, because that implies - * we are compiling eval code, in which case (cx->fp->flags & JSFRAME_EVAL) - * is true, and js_GetToken will have already selected JSOP_OBJECT instead of - * JSOP_REGEXP, to avoid all this RegExp object cloning business. - * - * Why clone regexp objects? ECMA specifies that when a regular expression - * literal is scanned, a RegExp object is created. In the spec, compilation - * and execution happen indivisibly, but in this implementation and many of - * its embeddings, code is precompiled early and re-executed in multiple - * threads, or using multiple global objects, or both, for efficiency. - * - * In such cases, naively following ECMA leads to wrongful sharing of RegExp - * objects, which makes for collisions on the lastIndex property (especially - * for global regexps) and on any ad-hoc properties. Also, __proto__ and - * __parent__ refer to the pre-compilation prototype and global objects, a - * pigeon-hole problem for instanceof tests. - */ -static JSBool -IndexRegExpClone(JSContext *cx, JSParseNode *pn, JSAtomListElement *ale, - JSCodeGenerator *cg) -{ - JSObject *varobj, *reobj; - JSClass *clasp; - JSFunction *fun; - JSRegExp *re; - uint16 *countPtr; - uintN cloneIndex; - - JS_ASSERT(!(cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO))); - - varobj = cx->fp->varobj; - clasp = OBJ_GET_CLASS(cx, varobj); - if (clasp == &js_FunctionClass) { - fun = (JSFunction *) JS_GetPrivate(cx, varobj); - countPtr = &fun->nregexps; - cloneIndex = *countPtr; - } else { - JS_ASSERT(clasp != &js_CallClass); - countPtr = &cg->treeContext.numGlobalVars; - cloneIndex = ALE_INDEX(ale); - } - - if ((cloneIndex + 1) >> 16) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_NEED_DIET, js_script_str); - return JS_FALSE; - } - if (cloneIndex >= *countPtr) - *countPtr = cloneIndex + 1; - - reobj = ATOM_TO_OBJECT(pn->pn_atom); - JS_ASSERT(OBJ_GET_CLASS(cx, reobj) == &js_RegExpClass); - re = (JSRegExp *) JS_GetPrivate(cx, reobj); - re->cloneIndex = cloneIndex; - return JS_TRUE; -} - -/* - * Macro to emit a bytecode followed by a uint16 immediate operand stored in - * big-endian order, used for arg and var numbers as well as for atomIndexes. - * NB: We use cx and cg from our caller's lexical environment, and return - * false on error. - */ -#define EMIT_UINT16_IMM_OP(op, i) \ - JS_BEGIN_MACRO \ - if (js_Emit3(cx, cg, op, ATOM_INDEX_HI(i), ATOM_INDEX_LO(i)) < 0) \ - return JS_FALSE; \ - JS_END_MACRO - -/* - * Emit a bytecode and its 2-byte constant (atom) index immediate operand. - * If the atomIndex requires more than 2 bytes, emit a prefix op whose 24-bit - * immediate operand indexes the atom in script->atomMap. - * - * If op has JOF_NAME mode, emit JSOP_FINDNAME to find and push the object in - * the scope chain in which the literal name was found, followed by the name - * as a string. This enables us to use the JOF_ELEM counterpart to op. - * - * Otherwise, if op has JOF_PROP mode, emit JSOP_LITERAL before op, to push - * the atom's value key. For JOF_PROP ops, the object being operated on has - * already been pushed, and JSOP_LITERAL will push the id, leaving the stack - * in the proper state for a JOF_ELEM counterpart. - * - * Otherwise, emit JSOP_LITOPX to push the atom index, then perform a special - * dispatch on op, but getting op's atom index from the stack instead of from - * an unsigned 16-bit immediate operand. - */ -static JSBool -EmitAtomIndexOp(JSContext *cx, JSOp op, jsatomid atomIndex, JSCodeGenerator *cg) -{ - uint32 mode; - JSOp prefixOp; - ptrdiff_t off; - jsbytecode *pc; - - if (atomIndex >= JS_BIT(16)) { - mode = (js_CodeSpec[op].format & JOF_MODEMASK); - if (op != JSOP_SETNAME) { - prefixOp = (mode == JOF_NAME) - ? JSOP_FINDNAME - : (mode == JOF_PROP) - ? JSOP_LITERAL - : JSOP_LITOPX; - off = js_EmitN(cx, cg, prefixOp, 3); - if (off < 0) - return JS_FALSE; - pc = CG_CODE(cg, off); - SET_LITERAL_INDEX(pc, atomIndex); - } - - switch (op) { - case JSOP_DECNAME: op = JSOP_DECELEM; break; - case JSOP_DECPROP: op = JSOP_DECELEM; break; - case JSOP_DELNAME: op = JSOP_DELELEM; break; - case JSOP_DELPROP: op = JSOP_DELELEM; break; - case JSOP_FORNAME: op = JSOP_FORELEM; break; - case JSOP_FORPROP: op = JSOP_FORELEM; break; - case JSOP_GETPROP: op = JSOP_GETELEM; break; - case JSOP_IMPORTPROP: op = JSOP_IMPORTELEM; break; - case JSOP_INCNAME: op = JSOP_INCELEM; break; - case JSOP_INCPROP: op = JSOP_INCELEM; break; - case JSOP_INITPROP: op = JSOP_INITELEM; break; - case JSOP_NAME: op = JSOP_GETELEM; break; - case JSOP_NAMEDEC: op = JSOP_ELEMDEC; break; - case JSOP_NAMEINC: op = JSOP_ELEMINC; break; - case JSOP_PROPDEC: op = JSOP_ELEMDEC; break; - case JSOP_PROPINC: op = JSOP_ELEMINC; break; - case JSOP_BINDNAME: return JS_TRUE; - case JSOP_SETNAME: op = JSOP_SETELEM; break; - case JSOP_SETPROP: op = JSOP_SETELEM; break; - default: JS_ASSERT(mode == 0); break; - } - - return js_Emit1(cx, cg, op) >= 0; - } - - EMIT_UINT16_IMM_OP(op, atomIndex); - return JS_TRUE; -} - -/* - * Slight sugar for EmitAtomIndexOp, again accessing cx and cg from the macro - * caller's lexical environment, and embedding a false return on error. - * XXXbe hey, who checks for fun->nvars and fun->nargs overflow?! - */ -#define EMIT_ATOM_INDEX_OP(op, atomIndex) \ - JS_BEGIN_MACRO \ - if (!EmitAtomIndexOp(cx, op, atomIndex, cg)) \ - 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; - if (op == JSOP_REGEXP && !IndexRegExpClone(cx, pn, ale, cg)) - return JS_FALSE; - return EmitAtomIndexOp(cx, op, ALE_INDEX(ale), cg); -} - -/* - * 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) -{ - JSStackFrame *fp; - JSObject *obj, *pobj; - JSClass *clasp; - JSBool optimizeGlobals; - JSAtom *atom; - JSProperty *prop; - JSScopeProperty *sprop; - JSOp op; - JSPropertyOp getter; - uintN attrs; - jsint slot; - JSAtomListElement *ale; - - JS_ASSERT(pn->pn_type == TOK_NAME); - if (pn->pn_slot >= 0 || pn->pn_op == JSOP_ARGUMENTS) - return JS_TRUE; - - /* QNAME references can never be optimized to use arg/var storage. */ - if (pn->pn_op == JSOP_QNAMEPART) - return JS_TRUE; - - /* - * A Script object can be used to split an eval into a compile step done - * at construction time, and an execute step done separately, possibly in - * a different scope altogether. We therefore cannot do any name-to-slot - * optimizations, but must lookup names at runtime. Note that script_exec - * ensures that its caller's frame has a Call object, so arg and var name - * lookups will succeed. - */ - if (cx->fp->flags & JSFRAME_SCRIPT_OBJECT) - 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. - */ - fp = cx->fp; - obj = fp->varobj; - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp != &js_FunctionClass && clasp != &js_CallClass) { - /* - * Optimize global variable accesses if there are at least 100 uses - * in unambiguous contexts, or failing that, if least half of all the - * uses of global vars/consts/functions are in loops. - */ - optimizeGlobals = (tc->globalUses >= 100 || - (tc->loopyGlobalUses && - tc->loopyGlobalUses >= tc->globalUses / 2)); - if (!optimizeGlobals) - return JS_TRUE; - } else { - optimizeGlobals = JS_FALSE; - } - - /* - * 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 (fp->scopeChain != obj || - js_InWithStatement(tc) || - js_InCatchBlock(tc, atom)) { - return JS_TRUE; - } - - op = pn->pn_op; - getter = NULL; -#ifdef __GNUC__ - attrs = slot = 0; /* quell GCC overwarning */ -#endif - if (optimizeGlobals) { - /* - * We are optimizing global variables, and there is no pre-existing - * global property named atom. If atom was declared via const or var, - * optimize pn to access fp->vars using the appropriate JOF_QVAR op. - */ - ATOM_LIST_SEARCH(ale, &tc->decls, atom); - if (!ale) { - /* Use precedes declaration, or name is never declared. */ - return JS_TRUE; - } - - attrs = (ALE_JSOP(ale) == JSOP_DEFCONST) - ? JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT - : JSPROP_ENUMERATE | JSPROP_PERMANENT; - - /* Index atom so we can map fast global number to name. */ - JS_ASSERT(tc->flags & TCF_COMPILING); - ale = js_IndexAtom(cx, atom, &((JSCodeGenerator *) tc)->atomList); - if (!ale) - return JS_FALSE; - - /* Defend against tc->numGlobalVars 16-bit overflow. */ - slot = ALE_INDEX(ale); - if ((slot + 1) >> 16) - return JS_TRUE; - - if ((uint16)(slot + 1) > tc->numGlobalVars) - tc->numGlobalVars = (uint16)(slot + 1); - } else { - /* - * 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 evaluates - * to false, due to JSPROP_PERMANENT. - */ - if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop)) - return JS_FALSE; - sprop = (JSScopeProperty *) prop; - if (sprop) { - if (pobj == obj) { - getter = sprop->getter; - attrs = sprop->attrs; - slot = (sprop->flags & SPROP_HAS_SHORTID) ? sprop->shortid : -1; - } - OBJ_DROP_PROPERTY(cx, pobj, prop); - } - } - - if (optimizeGlobals || getter) { - if (optimizeGlobals) { - switch (op) { - case JSOP_NAME: op = JSOP_GETGVAR; break; - case JSOP_SETNAME: op = JSOP_SETGVAR; break; - case JSOP_SETCONST: /* NB: no change */ break; - case JSOP_INCNAME: op = JSOP_INCGVAR; break; - case JSOP_NAMEINC: op = JSOP_GVARINC; break; - case JSOP_DECNAME: op = JSOP_DECGVAR; break; - case JSOP_NAMEDEC: op = JSOP_GVARDEC; break; - case JSOP_FORNAME: /* NB: no change */ break; - case JSOP_DELNAME: /* NB: no change */ 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); - } - } else if (getter == js_GetArgument || - (getter == js_CallClass.getProperty && - fp->fun && (uintN) slot < fp->fun->nargs)) { - 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); - } - } - if (op != pn->pn_op) { - pn->pn_op = op; - pn->pn_slot = slot; - } - pn->pn_attrs = attrs; - } - - if (pn->pn_slot < 0) { - /* - * We couldn't optimize pn, so it's not a global or local slot 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; -} - -/* - * Secret handshake with js_EmitTree's TOK_LP/TOK_NEW case logic, to flag all - * uses of JSOP_GETMETHOD that implicitly qualify the method-property name with - * a function:: prefix. All other JSOP_GETMETHOD and JSOP_SETMETHOD uses must - * be explicit, so need a distinct source note (SRC_PCDELTA rather than PCBASE) - * for round-tripping through the beloved decompiler. - */ -#define JSPROP_IMPLICIT_FUNCTION_NAMESPACE 0x100 - -static jssrcnote -SrcNoteForPropOp(JSParseNode *pn, JSOp op) -{ - return ((op == JSOP_GETMETHOD && - !(pn->pn_attrs & JSPROP_IMPLICIT_FUNCTION_NAMESPACE)) || - op == JSOP_SETMETHOD) - ? SRC_PCDELTA - : SRC_PCBASE; -} - -static JSBool -EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) -{ - JSParseNode *pn2, *pndot, *pnup, *pndown; - ptrdiff_t top; - - 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, SrcNoteForPropOp(pndot, pndot->pn_op), - CG_OFFSET(cg) - pndown->pn_offset) < 0) { - return JS_FALSE; - } - if (!EmitAtomOp(cx, pndot, pndot->pn_op, cg)) - return JS_FALSE; - - /* 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, SrcNoteForPropOp(pn, op), - 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 { - if (!EmitAtomOp(cx, pn, op, cg)) - return JS_FALSE; - } - return JS_TRUE; -} - -static JSBool -EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) -{ - ptrdiff_t top; - JSParseNode *left, *right, *next, temp; - 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 < JS_BIT(16)) { - left->pn_offset = next->pn_offset = top; - EMIT_UINT16_IMM_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 { - if (pn->pn_arity == PN_NAME) { - /* - * Set left and right so pn appears to be a TOK_LB node, instead - * of a TOK_DOT node (see the TOK_FOR/IN case in js_EmitTree). - */ - left = pn->pn_expr; - right = &temp; - right->pn_type = TOK_STRING; - right->pn_arity = PN_NULLARY; - right->pn_op = JSOP_STRING; - right->pn_atom = pn->pn_atom; - } 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 < JS_BIT(16)) { - left->pn_offset = right->pn_offset = top; - EMIT_UINT16_IMM_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; - ptrdiff_t off; - jsbytecode *pc; - 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; - - atomIndex = (jsatomid)ival; - if (atomIndex < JS_BIT(16)) { - EMIT_UINT16_IMM_OP(JSOP_UINT16, atomIndex); - return JS_TRUE; - } - - if (atomIndex < JS_BIT(24)) { - off = js_EmitN(cx, cg, JSOP_UINT24, 3); - if (off < 0) - return JS_FALSE; - pc = CG_CODE(cg, off); - SET_LITERAL_INDEX(pc, 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; - return EmitAtomIndexOp(cx, JSOP_NUMBER, ALE_INDEX(ale), cg); -} - -#if JS_HAS_SWITCH_STATEMENT -static JSBool -EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, - JSStmtInfo *stmtInfo) -{ - JSOp switchOp; - JSBool ok, hasDefault, constPropagated; - ptrdiff_t top, off, defaultOffset; - JSParseNode *pn2, *pn3, *pn4; - uint32 caseCount, tableLength; - JSParseNode **table; - jsdouble d; - jsint i, low, high; - jsval v; - JSAtom *atom; - JSAtomListElement *ale; - intN noteIndex; - size_t switchSize, tableSize; - jsbytecode *pc, *savepc; - - /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */ - switchOp = JSOP_TABLESWITCH; - ok = JS_TRUE; - hasDefault = constPropagated = 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; - caseCount = pn2->pn_count; - tableLength = 0; - table = NULL; - - if (caseCount == 0 || - (caseCount == 1 && - (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) { - caseCount = 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; - caseCount--; /* 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_NAME: - if (!pn4->pn_expr) { - ok = js_LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v); - if (!ok) - goto release; - if (!JSVAL_IS_VOID(v)) { - pn3->pn_val = v; - constPropagated = JS_TRUE; - break; - } - } - /* FALL THROUGH */ - 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) { - tableLength = (uint32)(high - low + 1); - if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount) - 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 + tableLength)); - } 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) * caseCount); - } - - /* - * 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; - JSBool beforeCases = JS_TRUE; - - /* 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 (!pn4) { - JS_ASSERT(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 (beforeCases) { - /* Switch note's second offset is to first JSOP_CASE. */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, - off - top)) { - return JS_FALSE; - } - beforeCases = JS_FALSE; - } - } - - /* Emit default even if no explicit default statement. */ - defaultOffset = EmitJump(cx, cg, JSOP_DEFAULT, 0); - if (defaultOffset < 0) - return JS_FALSE; - } else { - pc = CG_CODE(cg, top + JUMP_OFFSET_LEN); - - if (switchOp == JSOP_TABLESWITCH) { - /* Fill in switch bounds, which we know fit in 16-bit offsets. */ - SET_JUMP_OFFSET(pc, low); - pc += JUMP_OFFSET_LEN; - SET_JUMP_OFFSET(pc, high); - pc += JUMP_OFFSET_LEN; - - /* - * Use malloc to avoid arena bloat for programs with many switches. - * We free table if non-null at label out, so all control flow must - * exit this function through goto out or goto bad. - */ - if (tableLength != 0) { - tableSize = (size_t)tableLength * 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 < tableLength); - table[i] = pn3; - } - } - } else { - JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH); - - /* Fill in the number of cases. */ - SET_ATOM_INDEX(pc, caseCount); - pc += ATOM_INDEX_LEN; - } - - /* - * After this point, all control flow involving JSOP_TABLESWITCH - * must set ok and goto out to exit this function. To keep things - * simple, all switchOp cases exit that way. - */ - if (constPropagated) { - /* - * Skip switchOp, as we are not setting jump offsets in the two - * for loops below. We'll restore CG_NEXT(cg) from savepc after, - * unless there was an error. - */ - savepc = CG_NEXT(cg); - CG_NEXT(cg) = pc + 1; - if (switchOp == JSOP_TABLESWITCH) { - for (i = 0; i < (jsint)tableLength; i++) { - pn3 = table[i]; - if (pn3 && - (pn4 = pn3->pn_left) != NULL && - pn4->pn_type == TOK_NAME) { - /* Note a propagated constant with the const's name. */ - JS_ASSERT(!pn4->pn_expr); - ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList); - if (!ale) - goto bad; - CG_NEXT(cg) = pc; - if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t) - ALE_INDEX(ale)) < 0) { - goto bad; - } - } - pc += JUMP_OFFSET_LEN; - } - } else { - for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { - pn4 = pn3->pn_left; - if (pn4 && pn4->pn_type == TOK_NAME) { - /* Note a propagated constant with the const's name. */ - JS_ASSERT(!pn4->pn_expr); - ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList); - if (!ale) - goto bad; - CG_NEXT(cg) = pc; - if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t) - ALE_INDEX(ale)) < 0) { - goto bad; - } - } - pc += ATOM_INDEX_LEN + JUMP_OFFSET_LEN; - } - } - CG_NEXT(cg) = savepc; - } - } - - /* 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; - ok = js_EmitTree(cx, cg, pn4); - if (!ok) - goto out; - 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). */ - if (switchOp == JSOP_CONDSWITCH) { - pc = NULL; - JS_ASSERT(defaultOffset != -1); - ok = js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset), - off - (defaultOffset - top)); - if (!ok) - goto out; - } else { - pc = CG_CODE(cg, top); - ok = js_SetJumpOffset(cx, cg, pc, off); - if (!ok) - goto out; - pc += JUMP_OFFSET_LEN; - } - - /* Set the SRC_SWITCH note's offset operand to tell end of switch. */ - off = CG_OFFSET(cg) - top; - ok = js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off); - if (!ok) - goto out; - - 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. */ - for (i = 0; i < (jsint)tableLength; i++) { - pn3 = table[i]; - off = pn3 ? pn3->pn_offset - top : 0; - ok = js_SetJumpOffset(cx, cg, pc, off); - if (!ok) - goto out; - pc += JUMP_OFFSET_LEN; - } - } 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) - goto bad; - ale = js_IndexAtom(cx, atom, &cg->atomList); - if (!ale) - goto bad; - SET_ATOM_INDEX(pc, ALE_INDEX(ale)); - pc += ATOM_INDEX_LEN; - - off = pn3->pn_offset - top; - ok = js_SetJumpOffset(cx, cg, pc, off); - if (!ok) - goto out; - pc += JUMP_OFFSET_LEN; - } - } - -out: - if (table) - JS_free(cx, table); - return ok && js_PopStatementCG(cx, cg); - -bad: - ok = JS_FALSE; - goto out; -} -#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; - 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; - frame.flags = JS_HAS_COMPILE_N_GO_OPTION(cx) - ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO - : JSFRAME_COMPILING; - cx->fp = &frame; - ok = js_EmitTree(cx, cg, body); - cx->fp = fp; - if (!ok) - return JS_FALSE; - - fun->u.script = js_NewScriptFromCG(cx, cg, fun); - if (!fun->u.script) - return JS_FALSE; - JS_ASSERT(fun->interpreted); - 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; - ptrdiff_t 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; - -#if JS_HAS_XML_SUPPORT - if (pn->pn_arity == PN_NULLARY) { - if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0) - return JS_FALSE; - break; - } -#endif - - /* 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 = (uint16) (pn->pn_flags | TCF_IN_FUNCTION); - cg2->treeContext.tryCount = pn->pn_tryCount; - cg2->parent = cg; - 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; - JSProperty *prop; - JSScopeProperty *sprop; - uintN slot; - - obj = OBJ_GET_PARENT(cx, fun->object); - if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(fun->atom), - &pobj, &prop)) { - return JS_FALSE; - } - - JS_ASSERT(prop && pobj == obj); - sprop = (JSScopeProperty *) prop; - JS_ASSERT(sprop->getter == js_GetLocalVariable); - slot = sprop->shortid; - OBJ_DROP_PROPERTY(cx, pobj, prop); - - if (atomIndex >= JS_BIT(16)) { - /* - * Lots of literals in the outer function, so we have to emit - * [JSOP_LITOPX, atomIndex, JSOP_DEFLOCALFUN, var slot]. - */ - off = js_EmitN(cx, cg, JSOP_LITOPX, 3); - if (off < 0) - return JS_FALSE; - pc = CG_CODE(cg, off); - SET_LITERAL_INDEX(pc, atomIndex); - EMIT_UINT16_IMM_OP(JSOP_DEFLOCALFUN, slot); - } else { - /* Emit [JSOP_DEFLOCALFUN, var 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) { - JSBool emitIFEQ; - - /* Set stmtInfo type for later testing. */ - stmtInfo.type = STMT_FOR_IN_LOOP; - noteIndex = -1; - - /* - * If the left part is 'var x', emit code to define x if necessary - * using a prolog opcode, but do not emit a pop. If the left part - * is 'var x = i', emit prolog code to define x if necessary; then - * emit code to evaluate i, assign the result to x, and pop the - * result off the stack. - * - * All the logic to do this is implemented in the outer switch's - * TOK_VAR case, conditioned on pn_extra flags set by the parser. - * - * In the 'for (var x = i in o) ...' case, the js_EmitTree(...pn3) - * called here will generate the SRC_VAR note for the assignment - * op that sets x = i, hoisting the initialized var declaration - * out of the loop: 'var x = i; for (x in o) ...'. - * - * In the 'for (var x in o) ...' case, nothing but the prolog op - * (if needed) should be generated here, we must emit the SRC_VAR - * just before the JSOP_FOR* opcode in the switch on pn3->pn_type - * a bit below, so nothing is hoisted: 'for (var x in o) ...'. - */ - pn3 = pn2->pn_left; - if (pn3->pn_type == TOK_VAR && !js_EmitTree(cx, cg, pn3)) - return JS_FALSE; - - /* 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); - -#if JS_HAS_XML_SUPPORT - /* Emit a prefix opcode if 'for each (... in ...)' was used. */ - if (pn->pn_op != JSOP_NOP && js_Emit1(cx, cg, pn->pn_op) < 0) - return JS_FALSE; -#endif - - /* Compile a JSOP_FOR* bytecode based on the left hand side. */ - emitIFEQ = JS_TRUE; - switch (pn3->pn_type) { - case TOK_VAR: - pn3 = pn3->pn_head; - JS_ASSERT(pn3->pn_type == TOK_NAME); - if (!pn3->pn_expr && js_NewSrcNote(cx, cg, SRC_VAR) < 0) - return JS_FALSE; - /* FALL THROUGH */ - case TOK_NAME: - if (pn3->pn_slot >= 0) { - op = pn3->pn_op; - switch (op) { - case JSOP_GETARG: /* FALL THROUGH */ - case JSOP_SETARG: op = JSOP_FORARG; break; - case JSOP_GETVAR: /* FALL THROUGH */ - case JSOP_SETVAR: op = JSOP_FORVAR; break; - case JSOP_GETGVAR: - case JSOP_SETGVAR: op = JSOP_FORNAME; break; - default: JS_ASSERT(0); - } - } else { - 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_UINT16_IMM_OP(op, atomIndex); - } else { - if (!EmitAtomOp(cx, pn3, op, cg)) - return JS_FALSE; - } - break; - - case TOK_DOT: - useful = JS_TRUE; - if (!CheckSideEffects(cx, &cg->treeContext, pn3->pn_expr, - &useful)) { - return JS_FALSE; - } - if (!useful) { - if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg)) - return JS_FALSE; - break; - } - /* FALL THROUGH */ - -#if JS_HAS_XML_SUPPORT - case TOK_UNARYOP: -#endif -#if JS_HAS_LVALUE_RETURN - case TOK_LP: -#endif - 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). - */ - emitIFEQ = JS_FALSE; - 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; - -#if JS_HAS_LVALUE_RETURN - if (pn3->pn_type == TOK_LP) { - JS_ASSERT(pn3->pn_op == JSOP_SETCALL); - if (!js_EmitTree(cx, cg, pn3)) - return JS_FALSE; - if (!js_Emit1(cx, cg, JSOP_ENUMELEM)) - return JS_FALSE; - break; - } -#endif -#if JS_HAS_XML_SUPPORT - if (pn3->pn_type == TOK_UNARYOP) { - JS_ASSERT(pn3->pn_op == JSOP_BINDXMLNAME); - if (!js_EmitTree(cx, cg, pn3)) - return JS_FALSE; - if (!js_Emit1(cx, cg, JSOP_ENUMELEM)) - return JS_FALSE; - break; - } -#endif - - /* 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 (emitIFEQ) { - /* 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) { - if (js_Emit1(cx, cg, JSOP_POP2) < 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; - - /* - * 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. - * EmitBackPatchOp 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; - jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.gosub); - 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; - jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.catchJump); - 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 - * enterwith - * [< catchguard code >] if there's a catchguard - * [ifeq ] " " - * < catch block contents > - * leavewith - * goto non-local; finally applies - * - * If there's no catch block without a catchguard, the last - * 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) { - JS_ASSERT(cg->stackDepth == depth); - - /* Fix up and clean up previous catch block. */ - CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump); - - /* Set cx->throwing to protect cx->exception from the GC. */ - if (!js_Emit1(cx, cg, JSOP_THROWING) < 0) - return JS_FALSE; - - /* 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_UINT16_IMM_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 */ - 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 */ - 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. - */ - - /* leavewith, annotated so the decompiler knows to pop */ - off = cg->stackDepth - 1; - if (js_NewSrcNote2(cx, cg, SRC_CATCH, off) < 0 || - js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) { - return JS_FALSE; - } - - /* gosub , if required */ - if (pn->pn_kid3) { - jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, - &stmtInfo.gosub); - if (jmp < 0) - return JS_FALSE; - JS_ASSERT(cg->stackDepth == depth); - } - - /* This will get fixed up to jump to after catch/finally. */ - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) - return JS_FALSE; - jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, - &stmtInfo.catchJump); - if (jmp < 0) - return JS_FALSE; - if (!iter->pn_kid2) /* leave iter at last catch */ - break; - iter = iter->pn_kid2; - } - } - - /* - * We emit a [setsp][gosub] sequence for running finally code while - * letting an uncaught exception pass thrown from within the try in a - * try-finally. The [gosub] and [retsub] opcodes will take care of - * stacking and rethrowing any exception pending across the finally. - * - * For rethrowing after a try-catch(guard)-finally, we have a problem: - * all the guards have mismatched, leaving cx->exception still set but - * cx->throwing clear, so that no exception appears to be pending for - * [gosub] to stack and [retsub] to rethrow. We must emit a special - * [throwing] opcode in front of the [setsp][gosub]; this opcode will - * restore cx->throwing to true before running the finally. - * - * For rethrowing after a try-catch(guard) without a finally, we emit - * [setsp][exception][throw]. - */ - if (pn->pn_kid3 || - (catchJump != -1 && iter->pn_kid1->pn_expr)) { - /* - * Last discriminant jumps to the rethrow code sequence if no - * discriminants match. Target catchJump at the beginning of the - * rethrow sequence, just in case a guard expression throws and - * leaves the stack unbalanced. - */ - if (catchJump != -1 && iter->pn_kid1->pn_expr) { - CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump); - if (pn->pn_kid3 && !js_Emit1(cx, cg, JSOP_THROWING) < 0) - return JS_FALSE; - } - - /* - * 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_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth); - cg->stackDepth = depth; - - if (pn->pn_kid3) { - jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.gosub); - if (jmp < 0) - return JS_FALSE; - - JS_ASSERT(cg->stackDepth == depth); - JS_ASSERT((uintN)depth <= cg->maxStackDepth); - } else { - 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; - } - } - } - - /* - * 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. All [gosub] - * calls emitted before this point will push two stack slots, one - * for the pending exception (or JSVAL_HOLE if there is no pending - * exception) and one for the [retsub] pc-index. - */ - JS_ASSERT(cg->stackDepth == depth); - cg->stackDepth += 2; - 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; - } - - /* Restore stack depth budget to its balanced state. */ - JS_ASSERT(cg->stackDepth == depth + 2); - cg->stackDepth = depth; - } - if (!js_PopStatementCG(cx, cg)) - return JS_FALSE; - - 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 ((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_CONST && - (!(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); - pn3 = pn2->pn_expr; - if (pn->pn_op == JSOP_DEFCONST && - !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, - pn3)) { - return JS_FALSE; - } - if (!js_EmitTree(cx, cg, pn3)) - return JS_FALSE; - } - } - - /* - * 'for (var x in o) ...' and 'for (var x = i in o) ...' call the - * TOK_VAR case, but only the initialized case (a strange one that - * falls out of ECMA-262's grammar) wants to run past this point. - * Both cases must conditionally emit a JSOP_DEFVAR, above. Note - * that the parser error-checks to ensure that pn->pn_count is 1. - * - * XXX Narcissus keeps track of variable declarations in the node - * for the script being compiled, so there's no need to share any - * conditional prolog code generation there. We could do likewise, - * but it's a big change, requiring extra allocation, so probably - * not worth the trouble for SpiderMonkey. - */ - if ((pn->pn_extra & PNX_FORINVAR) && !pn2->pn_expr) - break; - - 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 if (pn2->pn_slot >= 0) { - EMIT_UINT16_IMM_OP(op, atomIndex); - } 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 & PNX_POPVAR) { - 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: -#if JS_HAS_XML_SUPPORT - if (pn->pn_arity == PN_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; - } -#endif - - JS_ASSERT(pn->pn_arity == PN_LIST); - 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->interpreted || - (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, cg, - JSREPORT_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 -#if JS_HAS_XML_SUPPORT - case TOK_UNARYOP: - JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME); - if (!js_EmitTree(cx, cg, pn2->pn_kid)) - return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) - 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_UINT16_IMM_OP((pn2->pn_op == JSOP_SETGVAR) - ? JSOP_GETGVAR - : (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_HAS_XML_SUPPORT - case TOK_UNARYOP: -#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 && - js_NewSrcNote2(cx, cg, SrcNoteForPropOp(pn2, pn2->pn_op), - 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)) { - if (pn2->pn_slot >= 0) { - EMIT_UINT16_IMM_OP(pn2->pn_op, atomIndex); - } else { - 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; -#if JS_HAS_XML_SUPPORT - case TOK_UNARYOP: - if (js_Emit1(cx, cg, JSOP_SETXMLNAME) < 0) - return JS_FALSE; - break; -#endif - 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 { -#if JS_HAS_XML_SUPPORT - case TOK_DBLCOLON: - if (pn->pn_arity == PN_NAME) { - if (!js_EmitTree(cx, cg, pn->pn_expr)) - return JS_FALSE; - if (!EmitAtomOp(cx, pn, pn->pn_op, cg)) - return JS_FALSE; - break; - } -#endif - /* 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 -#if JS_HAS_XML_SUPPORT - case TOK_AT: - case TOK_DEFAULT: - JS_ASSERT(pn->pn_arity == PN_UNARY); - /* FALL THROUGH */ -#endif - case TOK_UNARYOP: - /* Unary op, including unary +/-. */ - pn2 = pn->pn_kid; - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; - op = pn->pn_op; -#if JS_HAS_XML_SUPPORT - if (op == JSOP_XMLNAME && - js_NewSrcNote2(cx, cg, SRC_PCBASE, - CG_OFFSET(cg) - pn2->pn_offset) < 0) { - return JS_FALSE; - } -#endif - if (js_Emit1(cx, cg, 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; - - /* - * Allocate another stack slot for GC protection in case the initial - * value being post-incremented or -decremented is not a number, but - * converts to a jsdouble. In the TOK_NAME cases, op has 0 operand - * uses and 1 definition, so we don't need an extra stack slot -- we - * can use the one allocated for the def. - */ - if (pn2->pn_type != TOK_NAME && - (js_CodeSpec[op].format & JOF_POST) && - (uintN)++cg->stackDepth > cg->maxStackDepth) { - cg->maxStackDepth = cg->stackDepth; - } - - 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) { - /* Incrementing a declared const: just get its value. */ - op = ((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_CONST) - ? JSOP_GETGVAR - : JSOP_GETVAR; - } - atomIndex = (jsatomid) pn2->pn_slot; - EMIT_UINT16_IMM_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 -#if JS_HAS_XML_SUPPORT - case TOK_UNARYOP: - JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME); - if (!js_EmitTree(cx, cg, pn2->pn_kid)) - return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) - return JS_FALSE; - if (js_Emit1(cx, cg, op) < 0) - return JS_FALSE; - break; -#endif - default: - JS_ASSERT(0); - } - - if (pn2->pn_type != TOK_NAME && (js_CodeSpec[op].format & JOF_POST)) - --cg->stackDepth; - break; - - case TOK_DELETE: - /* - * Under ECMA 3, deleting a non-reference returns true -- but alas we - * must evaluate the operand if it appears it might have side effects. - */ - 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; -#if JS_HAS_XML_SUPPORT - case TOK_DBLDOT: - if (!EmitElemOp(cx, pn2, JSOP_DELDESC, cg)) - return JS_FALSE; - break; -#endif - case TOK_LB: - if (!EmitElemOp(cx, pn2, JSOP_DELELEM, cg)) - return JS_FALSE; - break; - default: - useful = JS_FALSE; - if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful)) - return JS_FALSE; - if (useful) { - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_POP) < 0) - return JS_FALSE; - } - if (js_Emit1(cx, cg, JSOP_TRUE) < 0) - return JS_FALSE; - } - break; - -#if JS_HAS_XML_SUPPORT - case TOK_FILTER: - if (!js_EmitTree(cx, cg, pn->pn_left)) - return JS_FALSE; - jmp = js_Emit3(cx, cg, JSOP_FILTER, 0, 0); - if (jmp < 0) - return JS_FALSE; - if (!js_EmitTree(cx, cg, pn->pn_right)) - return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_ENDFILTER) < 0) - return JS_FALSE; - CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); - break; -#endif - - 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: -#if JS_HAS_XML_SUPPORT - case TOK_DBLDOT: -#endif - /* - * 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. - * - * For E4X, if this expression is a dotted member reference, select - * JSOP_GETMETHOD instead of JSOP_GETPROP. ECMA-357 separates XML - * method lookup from the normal property id lookup done for native - * objects. - */ - pn2 = pn->pn_head; -#if JS_HAS_XML_SUPPORT - if (pn2->pn_type == TOK_DOT && pn2->pn_op != JSOP_GETMETHOD) { - JS_ASSERT(pn2->pn_op == JSOP_GETPROP); - pn2->pn_op = JSOP_GETMETHOD; - pn2->pn_attrs |= JSPROP_IMPLICIT_FUNCTION_NAMESPACE; - } -#endif - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; - - /* - * 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; - - /* Remember start of callable-object bytecode for decompilation hint. */ - off = top; - - /* - * 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_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num); - pn2 = pn2->pn_next; - } -#endif - - for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { - if (!EmitNumberOp(cx, atomIndex, cg)) - return JS_FALSE; - - /* FIXME 260106: 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; - } - - if (pn->pn_extra & PNX_ENDCOMMA) { - /* 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_UINT16_IMM_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_NewSrcNote2(cx, cg, SRC_LABEL, 0) < 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_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num); - break; - - case TOK_USESHARP: - EMIT_UINT16_IMM_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_UINT16_IMM_OP(op, atomIndex); - break; - } - /* FALL THROUGH */ - -#if JS_HAS_XML_SUPPORT - case TOK_XMLATTR: - case TOK_XMLSPACE: - case TOK_XMLTEXT: - case TOK_XMLCDATA: - case TOK_XMLCOMMENT: -#endif - 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; - -#if JS_HAS_XML_SUPPORT - case TOK_ANYNAME: -#endif - 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 */ - -#if JS_HAS_XML_SUPPORT - case TOK_XMLELEM: - case TOK_XMLLIST: - if (pn->pn_op == JSOP_XMLOBJECT) { - ok = EmitAtomOp(cx, pn, pn->pn_op, cg); - break; - } - - JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0); - switch (pn->pn_head ? pn->pn_head->pn_type : TOK_XMLLIST) { - case TOK_XMLETAGO: - JS_ASSERT(0); - /* FALL THROUGH */ - case TOK_XMLPTAGC: - case TOK_XMLSTAGO: - break; - default: - if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) - return JS_FALSE; - } - - for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { - if (pn2->pn_type == TOK_LC && - js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { - return JS_FALSE; - } - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; - if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) - return JS_FALSE; - } - - if (pn->pn_extra & PNX_XMLROOT) { - if (pn->pn_count == 0) { - JS_ASSERT(pn->pn_type == TOK_XMLLIST); - atom = cx->runtime->atomState.emptyAtom; - ale = js_IndexAtom(cx, atom, &cg->atomList); - if (!ale) - return JS_FALSE; - EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); - } - if (js_Emit1(cx, cg, pn->pn_op) < 0) - return JS_FALSE; - } -#ifdef DEBUG - else - JS_ASSERT(pn->pn_count != 0); -#endif - break; - - case TOK_XMLPTAGC: - if (pn->pn_op == JSOP_XMLOBJECT) { - ok = EmitAtomOp(cx, pn, pn->pn_op, cg); - break; - } - /* FALL THROUGH */ - - case TOK_XMLSTAGO: - case TOK_XMLETAGO: - { - uint32 i; - - if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) - return JS_FALSE; - - ale = js_IndexAtom(cx, - (pn->pn_type == TOK_XMLETAGO) - ? cx->runtime->atomState.etagoAtom - : cx->runtime->atomState.stagoAtom, - &cg->atomList); - if (!ale) - return JS_FALSE; - EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); - - JS_ASSERT(pn->pn_count != 0); - pn2 = pn->pn_head; - if (pn2->pn_type == TOK_LC && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) - return JS_FALSE; - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_ADD) < 0) - return JS_FALSE; - - for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) { - if (pn2->pn_type == TOK_LC && - js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { - return JS_FALSE; - } - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; - if ((i & 1) && pn2->pn_type == TOK_LC) { - if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0) - return JS_FALSE; - } - if (js_Emit1(cx, cg, - (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) { - return JS_FALSE; - } - } - - ale = js_IndexAtom(cx, - (pn->pn_type == TOK_XMLPTAGC) - ? cx->runtime->atomState.ptagcAtom - : cx->runtime->atomState.tagcAtom, - &cg->atomList); - if (!ale) - return JS_FALSE; - EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); - if (js_Emit1(cx, cg, JSOP_ADD) < 0) - return JS_FALSE; - - if ((pn->pn_extra & PNX_XMLROOT) && js_Emit1(cx, cg, pn->pn_op) < 0) - return JS_FALSE; - break; - } - - case TOK_XMLNAME: - if (pn->pn_arity == PN_LIST) { - JS_ASSERT(pn->pn_count != 0); - for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; - if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) - return JS_FALSE; - } - } else { - JS_ASSERT(pn->pn_arity == PN_NULLARY); - ok = EmitAtomOp(cx, pn, pn->pn_op, cg); - } - break; - - case TOK_XMLPI: - ale = js_IndexAtom(cx, pn->pn_atom2, &cg->atomList); - if (!ale) - return JS_FALSE; - if (!EmitAtomIndexOp(cx, JSOP_STRING, ALE_INDEX(ale), cg)) - return JS_FALSE; - if (!EmitAtomOp(cx, pn, JSOP_XMLPI, cg)) - return JS_FALSE; - break; -#endif /* JS_HAS_XML_SUPPORT */ - - 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; -} - -JS_FRIEND_API(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; - setvbuf(fp, NULL, _IONBF, 0); - } - 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(¬es[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 deleted file mode 100644 index 6ec4600b4..000000000 --- a/src/dom/js/jsemit.h +++ /dev/null @@ -1,592 +0,0 @@ -/* -*- 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 */ - uint16 flags; /* statement state flags, see below */ - uint16 numGlobalVars; /* max. no. of global variables/regexps */ - uint32 tryCount; /* total count of try statements parsed */ - uint32 globalUses; /* optimizable global var uses in total */ - uint32 loopyGlobalUses;/* optimizable global var uses in loops */ - 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 TCF_HAS_DEFXMLNS 0x100 /* default xml namespace = ...; parsed */ - -#define TREE_CONTEXT_INIT(tc) \ - ((tc)->flags = (tc)->numGlobalVars = 0, \ - (tc)->tryCount = (tc)->globalUses = (tc)->loopyGlobalUses = 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_GET_TARGET(sd) (JS_ASSERT(JT_HAS_TAG((sd)->target)), \ - JT_CLR_TAG((sd)->target)) -#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)) - -/* Avoid asserting twice by expanding SD_GET_TARGET in the "then" clause. */ -#define SD_SPAN(sd,pivot) (SD_GET_TARGET(sd) \ - ? JT_CLR_TAG((sd)->target)->offset - (pivot) \ - : 0) - -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 */ - ptrdiff_t spanDepTodo; /* offset from main.base of potentially - unoptimized spandeps */ - - uintN emitLevel; /* js_EmitTree recursion level */ - JSAtomList constList; /* compile time constants */ - JSCodeGenerator *parent; /* Enclosing function or global context */ -}; - -#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); - -/* - * Define and lookup a primitive jsval associated with the const named by atom. - * js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn - * and saves the const's value in cg->constList, if it can be used at compile - * time. It returns true unless an error occurred. - * - * If the initializer's value could not be saved, js_LookupCompileTimeConstant - * calls will return the undefined value. js_LookupCompileTimeConstant tries - * to find a const value memorized for atom, returning true with *vp set to a - * value other than undefined if the constant was found, true with *vp set to - * JSVAL_VOID if not found, and false on error. - */ -extern JSBool -js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - JSParseNode *pn); - -extern JSBool -js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - jsval *vp); - -/* - * 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, /* distance from comma-operator to next POP, - or from CONDSWITCH to first CASE opcode -- - or SRC_PCBASE variant for obj.function::foo - gets and sets */ - 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, /* distance back from annotated get- or setprop - op to 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 deleted file mode 100644 index c637a5630..000000000 --- a/src/dom/js/jsexn.c +++ /dev/null @@ -1,1186 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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 -#include -#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 "jsdbgapi.h" -#include "jsexn.h" -#include "jsfun.h" -#include "jsinterp.h" -#include "jsnum.h" -#include "jsopcode.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; - -static JSErrorReport * -CopyErrorReport(JSContext *cx, JSErrorReport *report) -{ - /* - * We use a single malloc block to make a deep copy of JSErrorReport with - * the following layout: - * JSErrorReport - * array of copies of report->messageArgs - * jschar array with characters for all messageArgs - * jschar array with characters for ucmessage - * jschar array with characters for uclinebuf and uctokenptr - * char array with characters for linebuf and tokenptr - * char array with characters for filename - * Such layout does not need any extra alignment padding. - */ - size_t filenameSize; - size_t linebufSize; - size_t uclinebufSize; - size_t ucmessageSize; - size_t i, argsArraySize, argsCopySize, argSize; - size_t mallocSize; - JSErrorReport *copy; - uint8 *cursor; - -#define JS_CHARS_SIZE(jschars) ((js_strlen(jschars) + 1) * sizeof(jschar)) - - filenameSize = report->filename ? strlen(report->filename) + 1 : 0; - linebufSize = report->linebuf ? strlen(report->linebuf) + 1 : 0; - uclinebufSize = report->uclinebuf ? JS_CHARS_SIZE(report->uclinebuf) : 0; - ucmessageSize = 0; - argsArraySize = 0; - argsCopySize = 0; - if (report->ucmessage) { - ucmessageSize = JS_CHARS_SIZE(report->ucmessage); - if (report->messageArgs) { - for (i = 0; report->messageArgs[i]; ++i) - argsCopySize += JS_CHARS_SIZE(report->messageArgs[i]); - - /* Non-null messageArgs should have at least one non-null arg. */ - JS_ASSERT(i != 0); - argsArraySize = (i + 1) * sizeof(const jschar *); - } - } - - /* - * The mallocSize can not overflow since it represents the sum of the - * sizes of already allocated objects. - */ - mallocSize = sizeof(JSErrorReport) + argsArraySize + argsCopySize + - ucmessageSize + uclinebufSize + linebufSize + filenameSize; - cursor = (uint8 *)JS_malloc(cx, mallocSize); - if (!cursor) - return NULL; - - copy = (JSErrorReport *)cursor; - memset(cursor, 0, sizeof(JSErrorReport)); - cursor += sizeof(JSErrorReport); - - if (argsArraySize != 0) { - copy->messageArgs = (const jschar **)cursor; - cursor += argsArraySize; - for (i = 0; report->messageArgs[i]; ++i) { - copy->messageArgs[i] = (const jschar *)cursor; - argSize = JS_CHARS_SIZE(report->messageArgs[i]); - memcpy(cursor, report->messageArgs[i], argSize); - cursor += argSize; - } - copy->messageArgs[i] = NULL; - JS_ASSERT(cursor == (uint8 *)copy->messageArgs[0] + argsCopySize); - } - - if (report->ucmessage) { - copy->ucmessage = (const jschar *)cursor; - memcpy(cursor, report->ucmessage, ucmessageSize); - cursor += ucmessageSize; - } - - if (report->uclinebuf) { - copy->uclinebuf = (const jschar *)cursor; - memcpy(cursor, report->uclinebuf, uclinebufSize); - cursor += uclinebufSize; - if (report->uctokenptr) { - copy->uctokenptr = copy->uclinebuf + (report->uctokenptr - - report->uclinebuf); - } - } - - if (report->linebuf) { - copy->linebuf = (const char *)cursor; - memcpy(cursor, report->linebuf, linebufSize); - cursor += linebufSize; - if (report->tokenptr) { - copy->tokenptr = copy->linebuf + (report->tokenptr - - report->linebuf); - } - } - - if (report->filename) { - copy->filename = (const char *)cursor; - memcpy(cursor, report->filename, filenameSize); - } - JS_ASSERT(cursor + filenameSize == (uint8 *)copy + mallocSize); - - /* Copy non-pointer members. */ - copy->lineno = report->lineno; - copy->errorNumber = report->errorNumber; - - /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */ - copy->flags = report->flags; - -#undef JS_CHARS_SIZE - return copy; -} - -/* - * Copy everything interesting about an error into allocated memory. - */ -static JSExnPrivate * -exn_newPrivate(JSContext *cx, JSErrorReport *report) -{ - JSExnPrivate *newPrivate; - - newPrivate = (JSExnPrivate *)JS_malloc(cx, sizeof (JSExnPrivate)); - if (!newPrivate) - return NULL; - newPrivate->errorReport = CopyErrorReport(cx, report); - if (!newPrivate->errorReport) { - JS_free(cx, newPrivate); - return NULL; - } - return newPrivate; -} - -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) { - if (privateData->errorReport) - JS_free(cx, privateData->errorReport); - JS_free(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; - -/* Limit the stackbuf length to a reasonable value to avoid overflow checks. */ -#define STACK_LENGTH_LIMIT JS_BIT(20) - -#define APPEND_CHAR_TO_STACK(c) \ - JS_BEGIN_MACRO \ - if (stacklen == stackmax) { \ - void *ptr_; \ - if (stackmax >= STACK_LENGTH_LIMIT) \ - goto done; \ - 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 (length_ > stackmax - stacklen) { \ - void *ptr_; \ - if (stackmax >= STACK_LENGTH_LIMIT || \ - length_ >= STACK_LENGTH_LIMIT - stacklen) { \ - goto done; \ - } \ - 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, JSVAL_TO_OBJECT(fp->argv[-2]), callerid, - JSACC_READ, &v /* ignored */); - 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 -#undef STACK_LENGTH_LIMIT - -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); -} - -/* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8 - with these two functions. */ -static JSString * -FilenameToString(JSContext *cx, const char *filename) -{ - return JS_NewStringCopyZ(cx, filename); -} - -static const char * -StringToFilename(JSContext *cx, JSString *str) -{ - return JS_GetStringBytes(str); -} - -static JSBool -Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSBool ok; - uint32 lineno; - JSString *message, *filename; - JSStackFrame *fp; - - 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]), - ATOM_TO_JSID(cx->runtime->atomState - .classPrototypeAtom), - rval); - if (!ok) - goto out; - obj = js_NewObject(cx, &ExceptionClass, JSVAL_TO_OBJECT(*rval), 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; - } - argv[0] = STRING_TO_JSVAL(message); - } 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; - } - argv[1] = STRING_TO_JSVAL(filename); - fp = NULL; - } else { - fp = JS_GetScriptedCaller(cx, NULL); - if (fp) { - filename = FilenameToString(cx, fp->script->filename); - if (!filename) { - ok = JS_FALSE; - goto out; - } - } else { - filename = cx->runtime->emptyString; - } - } - - /* Set the 'lineNumber' property. */ - if (argc > 2) { - ok = js_ValueToECMAUint32(cx, argv[2], &lineno); - if (!ok) - goto out; - } else { - if (!fp) - fp = JS_GetScriptedCaller(cx, NULL); - lineno = (fp && fp->pc) ? js_PCToLineNumber(cx, fp->script, fp->pc) : 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, - ATOM_TO_JSID(cx->runtime->atomState.nameAtom), - &v)) { - return JS_FALSE; - } - name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; - *rval = STRING_TO_JSVAL(name); - - if (!JS_GetProperty(cx, obj, js_message_str, &v)) - return JS_FALSE; - message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) - : cx->runtime->emptyString; - - if (JSSTRING_LENGTH(message) != 0) { - name_length = JSSTRING_LENGTH(name); - message_length = JSSTRING_LENGTH(message); - length = (name_length ? name_length + 2 : 0) + message_length; - cp = chars = (jschar*) JS_malloc(cx, (length + 1) * sizeof(jschar)); - if (!chars) - return JS_FALSE; - - if (name_length) { - 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 *vp; - JSString *name, *message, *filename, *lineno_as_str, *result; - uint32 lineno; - size_t lineno_length, name_length, message_length, filename_length, length; - jschar *chars, *cp; - - vp = argv + argc; /* beginning of explicit local roots */ - - if (!OBJ_GET_PROPERTY(cx, obj, - ATOM_TO_JSID(cx->runtime->atomState.nameAtom), - rval)) { - return JS_FALSE; - } - name = js_ValueToString(cx, *rval); - if (!name) - return JS_FALSE; - *rval = STRING_TO_JSVAL(name); - - if (!JS_GetProperty(cx, obj, js_message_str, &vp[0]) || - !(message = js_ValueToSource(cx, vp[0]))) { - return JS_FALSE; - } - vp[0] = STRING_TO_JSVAL(message); - - if (!JS_GetProperty(cx, obj, js_filename_str, &vp[1]) || - !(filename = js_ValueToSource(cx, vp[1]))) { - return JS_FALSE; - } - vp[1] = STRING_TO_JSVAL(filename); - - if (!JS_GetProperty(cx, obj, js_lineno_str, &vp[2]) || - !js_ValueToECMAUint32 (cx, vp[2], &lineno)) { - return JS_FALSE; - } - - if (lineno != 0) { - lineno_as_str = js_ValueToString(cx, vp[2]); - if (!lineno_as_str) - 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,3}, -#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]; - - if (!js_EnterLocalRootScope(cx)) - return NULL; - - /* 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]) - break; - - /* 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) - break; - - /* Make a constructor function for the current name. */ - fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0); - if (!fun) - break; - - /* 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)) { - break; - } - - /* proto bootstrap bit from JS_InitClass omitted. */ - nameString = JS_NewStringCopyZ(cx, exceptions[i].name); - if (!nameString) - break; - - /* Add the name property to the prototype. */ - if (!JS_DefineProperty(cx, protos[i], js_name_str, - STRING_TO_JSVAL(nameString), - NULL, NULL, - JSPROP_ENUMERATE)) { - break; - } - } - - js_LeaveLocalRootScope(cx); - if (exceptions[i].name) - 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; - jsval tv[4]; - JSTempValueRooter tvr; - 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; - - /* After this point the control must flow through the label out. */ - cx->creatingException = JS_TRUE; - - /* Protect the newly-created strings below from nesting GCs. */ - memset(tv, 0, sizeof tv); - JS_PUSH_TEMP_ROOT(cx, sizeof tv / sizeof tv[0], tv, &tvr); - - /* - * 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. - */ - ok = js_GetClassPrototype(cx, exceptions[exn].name, &errProto); - if (!ok) - goto out; - tv[0] = OBJECT_TO_JSVAL(errProto); - - errObject = js_NewObject(cx, &ExceptionClass, errProto, NULL); - if (!errObject) { - ok = JS_FALSE; - goto out; - } - tv[1] = OBJECT_TO_JSVAL(errObject); - - messageStr = JS_NewStringCopyZ(cx, message); - if (!messageStr) { - ok = JS_FALSE; - goto out; - } - tv[2] = STRING_TO_JSVAL(messageStr); - - if (reportp) { - filenameStr = JS_NewStringCopyZ(cx, reportp->filename); - if (!filenameStr) { - ok = JS_FALSE; - goto out; - } - tv[3] = STRING_TO_JSVAL(filenameStr); - 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)); - - JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); - - /* Flag the error report passed in to indicate an exception was raised. */ - reportp->flags |= JSREPORT_EXCEPTION; - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - cx->creatingException = JS_FALSE; - return ok; -} -#endif /* JS_HAS_ERROR_EXCEPTIONS */ - -#if JS_HAS_EXCEPTIONS - -JSBool -js_ReportUncaughtException(JSContext *cx) -{ - jsval exn, *vp; - JSObject *exnObject; - void *mark; - JSErrorReport *reportp, report; - JSString *str; - const char *bytes; - JSBool ok; - - if (!JS_IsExceptionPending(cx)) - return JS_TRUE; - - if (!JS_GetPendingException(cx, &exn)) - return JS_FALSE; - - /* - * Because js_ValueToString below could error and an exception object - * could become unrooted, we must root exnObject. Later, if exnObject is - * non-null, we need to root other intermediates, so allocate an operand - * stack segment to protect all of these values. - */ - if (JSVAL_IS_PRIMITIVE(exn)) { - exnObject = NULL; - vp = NULL; -#ifdef __GNUC__ /* suppress bogus gcc warnings */ - mark = NULL; -#endif - } else { - exnObject = JSVAL_TO_OBJECT(exn); - vp = js_AllocStack(cx, 5, &mark); - if (!vp) { - ok = JS_FALSE; - goto out; - } - vp[0] = exn; - } - -#if JS_HAS_ERROR_EXCEPTIONS - reportp = js_ErrorFromException(cx, exn); -#else - reportp = NULL; -#endif - - /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ - str = js_ValueToString(cx, exn); - if (!str) { - bytes = "unknown (can't convert to string)"; - } else { - if (vp) - vp[1] = STRING_TO_JSVAL(str); - bytes = js_GetStringBytes(str); - } - ok = JS_TRUE; - - if (!reportp && - exnObject && - OBJ_GET_CLASS(cx, exnObject) == &ExceptionClass) { - const char *filename; - uint32 lineno; - - ok = JS_GetProperty(cx, exnObject, js_message_str, &vp[2]); - if (!ok) - goto out; - if (JSVAL_IS_STRING(vp[2])) - bytes = JS_GetStringBytes(JSVAL_TO_STRING(vp[2])); - - ok = JS_GetProperty(cx, exnObject, js_filename_str, &vp[3]); - if (!ok) - goto out; - str = js_ValueToString(cx, vp[3]); - if (!str) { - ok = JS_FALSE; - goto out; - } - filename = StringToFilename(cx, str); - - ok = JS_GetProperty(cx, exnObject, js_lineno_str, &vp[4]); - if (!ok) - goto out; - ok = js_ValueToECMAUint32 (cx, vp[4], &lineno); - if (!ok) - goto out; - - reportp = &report; - memset(&report, 0, sizeof report); - report.filename = filename; - report.lineno = (uintN) lineno; - } - - if (!reportp) { - 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); - } - - JS_ClearPendingException(cx); -out: - if (exnObject) - js_FreeStack(cx, mark); - return ok; -} - -#endif /* JS_HAS_EXCEPTIONS */ diff --git a/src/dom/js/jsexn.h b/src/dom/js/jsexn.h deleted file mode 100644 index aeaab0a58..000000000 --- a/src/dom/js/jsexn.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 2237dbd47..000000000 --- a/src/dom/js/jsfile.c +++ /dev/null @@ -1,2720 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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 ----------------- */ -#if defined(XP_WIN) || defined(XP_OS2) -# include -# include -# include -# include -# define FILESEPARATOR '\\' -# define FILESEPARATOR2 '/' -# define CURRENT_DIR "c:\\" -# define POPEN _popen -# define PCLOSE _pclose -#elif defined(XP_UNIX) || defined(XP_BEOS) -# include -# include -# include -# include -# 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 - -/* 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"); \ - } \ - 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"); \ - } \ - 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) - XXX Should this be a real function returning a JSBool result (and getting - some typesafety help from the compiler?). -*/ -#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; - 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) -{ - if (!filename) - return JS_FALSE; - - return filename[0] == PIPE_SYMBOL || - filename[strlen(filename) - 1] == PIPE_SYMBOL; -} - -static JSBool -js_isAbsolute(const char *name) -{ -#if defined(XP_WIN) || defined(XP_OS2) - return *name && name[1] == ':'; -#else - return (name[0] -# if defined(XP_UNIX) || defined(XP_BEOS) - == -# else - != -# endif - FILESEPARATOR); -#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 = JS_malloc(cx, len + strlen(name) + 2); - - if (!result) - return NULL; - - strcpy(result, base); - - if (base[len - 1] != FILESEPARATOR && base[len - 1] != FILESEPARATOR2) { - 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; - - index = strlen(pathname)-1; - - /* Chop off trailing seperators. */ - 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 = JS_malloc(cx, aux - index + 1); - if (!result) - return NULL; - strncpy(result, pathname + index + 1, aux - index); - result[aux - index] = '\0'; - return result; -} - -/* - * Returns everything but the last component from a path name. - * Returned string must be freed. - */ -static char * -js_fileDirectoryName(JSContext *cx, const char *pathname) -{ - char *result; - const char *cp, *end; - size_t pathsize; - - end = pathname + strlen(pathname); - cp = end - 1; - - /* If this is already a directory, chop off the trailing /s. */ - while (cp >= pathname) { - if (*cp != FILESEPARATOR && *cp != FILESEPARATOR2) - break; - --cp; - } - - if (cp < pathname && end != pathname) { - /* There were just /s, return the root. */ - result = JS_malloc(cx, 1 + 1); /* The separator + trailing NUL. */ - result[0] = FILESEPARATOR; - result[1] = '\0'; - return result; - } - - /* Now chop off the last portion. */ - while (cp >= pathname) { - if (*cp == FILESEPARATOR || *cp == FILESEPARATOR2) - break; - --cp; - } - - /* Check if this is a leaf. */ - if (cp < pathname) { - /* It is, return "pathname/". */ - if (end[-1] == FILESEPARATOR || end[-1] == FILESEPARATOR2) { - /* Already has its terminating /. */ - return JS_strdup(cx, pathname); - } - - pathsize = end - pathname + 1; - result = JS_malloc(cx, pathsize + 1); - if (!result) - return NULL; - - strcpy(result, pathname); - result[pathsize - 1] = FILESEPARATOR; - result[pathsize] = '\0'; - - return result; - } - - /* Return everything up to and including the seperator. */ - pathsize = cp - pathname + 1; - result = JS_malloc(cx, pathsize + 1); - if (!result) - return NULL; - - strncpy(result, pathname, pathsize); - result[pathsize] = '\0'; - - 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 < j && path[i] == ' ') - i++; - while (j >= 0 && path[j] == ' ') - j--; - - tmp = JS_malloc(cx, j-i+2); - if (!tmp) - return NULL; - - strncpy(tmp, path + i, j - i + 1); - tmp[j - i + 1] = '\0'; - - path = tmp; - - /* Pipe support. */ - if (js_filenameHasAPipe(path)) - return path; - - /* file:// support. */ - if (!strncmp(path, URL_PREFIX, strlen(URL_PREFIX))) { - tmp = js_canonicalPath(cx, path + strlen(URL_PREFIX)); - JS_free(cx, path); - return tmp; - } - - if (!js_isAbsolute(path)) { - tmp = js_absolutePath(cx, path); - if (!tmp) - return NULL; - path = tmp; - } - - result = JS_strdup(cx, ""); - - current = path; - - base = js_fileBaseName(cx, current); - dir = js_fileDirectoryName(cx, current); - - while (strcmp(dir, current)) { - if (!strcmp(base, "..")) { - back++; - } else { - if (back > 0) { - back--; - } else { - tmp = result; - result = JS_malloc(cx, strlen(base) + 1 + strlen(tmp) + 1); - if (!result) - goto out; - - 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) - goto out; - - 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); - } - -out: - if (tmp) - JS_free(cx, tmp); - if (dir) - JS_free(cx, dir); - if (base) - JS_free(cx, base); - if (current) - 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 { - /* 0x800 >= onechar <= MAX_UCS2 */ - numUTF8bytes = 3; - } - - 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; -} - -/* 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 = 0, 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;count0) { - 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; - - default: - /* Not reached. */ - JS_ASSERT(0); - } - - 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 = 0, 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;count0) { - 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; - - default: - /* Not reached. */ - JS_ASSERT(0); - } - - 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 = 0, i, j; - unsigned char *utfbuf; - - switch (mode) { - case ASCII: - aux = (unsigned char*)JS_malloc(cx, len); - if (!aux) - return 0; - - for (i = 0; iisNative) - ? 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;countisNative) - ? PR_Write(file->handle, utfbuf, i) - : fwrite(utfbuf, 1, i, file->nativehandle); - - if (jisNative) - ? PR_Write(file->handle, buf, len*2) >> 1 - : fwrite(buf, 1, len*2, file->nativehandle) >> 1; - - if (count == -1) - return 0; - break; - - default: - /* Not reached. */ - JS_ASSERT(0); - } - - 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) { - /* It doesn't make sense for a pipe of stdstream. */ - return JS_FALSE; - } - - return PR_Access(file->path, PR_ACCESS_EXISTS) == PR_SUCCESS; -} - -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; - } - - if (file->isPipe) { - /* Is this pipe open for reading? */ - return file->path[0] == PIPE_SYMBOL; - } - - 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; - } - - if(file->isPipe) { - /* Is this pipe open for writing? */ - return file->path[strlen(file->path)-1] == PIPE_SYMBOL; - } - - 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; - } - - return info.type == PR_FILE_FILE; - } - - /* This 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; - } - - return info.type == PR_FILE_DIRECTORY; - } - - /* This 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); - return JS_FALSE; - } - - return INT_TO_JSVAL(info.size); - -out: - return JSVAL_VOID; -} - -/* - * Return the parent object - */ -static JSBool -js_parent(JSContext *cx, JSFile *file, jsval *resultp) -{ - char *str; - - /* Since we only care about pipes and native files, return NULL. */ - if (file->isNative) { - *resultp = JSVAL_VOID; - return JS_TRUE; - } - - str = js_fileDirectoryName(cx, file->path); - if (!str) - return JS_FALSE; - - /* If the directory is equal to the original path, we're at the root. */ - if (!strcmp(file->path, str)) { - *resultp = JSVAL_NULL; - } else { - JSObject *obj = js_NewFileObject(cx, str); - if (!obj) { - JS_free(cx, str); - return JS_FALSE; - } - *resultp = OBJECT_TO_JSVAL(obj); - } - - JS_free(cx, str); - return JS_TRUE; -} - -static JSBool -js_name(JSContext *cx, JSFile *file, jsval *vp) -{ - char *name; - JSString *str; - - if (file->isPipe) { - *vp = JSVAL_VOID; - return JS_TRUE; - } - - name = js_fileBaseName(cx, file->path); - if (!name) - return JS_FALSE; - - str = JS_NewString(cx, name, strlen(name)); - if (!str) { - JS_free(cx, name); - return JS_FALSE; - } - - *vp = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -/* ------------------------------ 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; - - mode = NULL; - - 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, 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 { - int i = 0; - 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[i++] = 'r'; -#ifndef XP_UNIX - pipemode[i++] = file->type==UTF8 ? 'b' : 't'; -#endif - pipemode[i++] = '\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[i++] = 'w'; -#ifndef XP_UNIX - pipemode[i++] = file->type==UTF8 ? 'b' : 't'; -#endif - pipemode[i++] = '\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; - } - -good: - file->isOpen = JS_TRUE; - *rval = JSVAL_TRUE; - return JS_TRUE; - -out: - if(mode) - JS_free(cx, mode); - 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: - 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; itype); - 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; i262144)?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 = NULL, *tmp; - int32 offset, read; - intN room; - jschar data, data2; - - SECURITY_CHECK(cx, NULL, "readln", file); - JSFILE_CHECK_READ; - - buf = JS_malloc(cx, MAX_LINE_LENGTH * sizeof data); - if (!buf) - return JS_FALSE; - - room = MAX_LINE_LENGTH - 1; - offset = 0; - - for (;;) { - read = js_FileRead(cx, file, &data, 1, file->type); - if (read < 0) - goto out; - if (read == 0) - goto eof; - - switch (data) { - case '\r': - read = js_FileRead(cx, file, &data2, 1, file->type); - if (read < 0) - goto out; - - if (read == 1 && data2 != '\n') { - /* We read one char too far. Buffer it. */ - file->charBuffer = data2; - file->charBufferUsed = JS_TRUE; - } - - /* Fall through. */ - case '\n': - goto done; - - default: - if (--room < 0) { - tmp = JS_realloc(cx, buf, - (offset + MAX_LINE_LENGTH) * sizeof data); - if (!tmp) - goto out; - - room = MAX_LINE_LENGTH - 1; - buf = tmp; - } - - buf[offset++] = data; - break; - } - } - -eof: - if (offset == 0) { - *rval = JSVAL_NULL; - return JS_TRUE; - } - -done: - buf[offset] = 0; - tmp = JS_realloc(cx, buf, (offset + 1) * sizeof data); - if (!tmp) - goto out; - - str = JS_NewUCString(cx, tmp, offset); - if (!str) - goto out; - - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; - -out: - if (buf) - JS_free(cx, buf); - - 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; - JSBool lineok = JS_FALSE; - - SECURITY_CHECK(cx, NULL, "readAll", file); - JSFILE_CHECK_READ; - - array = JS_NewArrayObject(cx, 0, NULL); - if (!array) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(array); - - len = 0; - - lineok = file_readln(cx, obj, 0, NULL, &line); - while (lineok && !JSVAL_IS_NULL(line)) { - JS_SetElement(cx, array, len++, &line); - lineok = file_readln(cx, obj, 0, NULL, &line); - } - -out: - return lineok; -} - -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; - } - - 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; - - 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; - - if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { - /* Replace obj with a new File object. */ - obj = JS_NewObject(cx, &file_class, NULL, NULL); - if (!obj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - } - - 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]); - return JS_FALSE; - } - - file = file_init(cx, obj, JS_GetStringBytes(str)); - if (!file) - return JS_FALSE; - - SECURITY_CHECK(cx, NULL, "constructor", file); - - return JS_TRUE; -} - -/* -------------------- 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 *bytes; - JSString *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); - if (!js_parent(cx, file, vp)) - return JS_FALSE; - break; - case FILE_PATH: - str = JS_NewStringCopyZ(cx, file->path); - if (!str) - return JS_FALSE; - *vp = STRING_TO_JSVAL(str); - break; - case FILE_NAME: - if (!js_name(cx, file, vp)) - return JS_FALSE; - 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"); - bytes = JS_malloc(cx, MODE_SIZE); - bytes[0] = '\0'; - flag = JS_FALSE; - - if ((file->mode&PR_RDONLY)==PR_RDONLY) { - if (flag) strcat(bytes, ","); - strcat(bytes, "read"); - flag = JS_TRUE; - } - if ((file->mode&PR_WRONLY)==PR_WRONLY) { - if (flag) strcat(bytes, ","); - strcat(bytes, "write"); - flag = JS_TRUE; - } - if ((file->mode&PR_RDWR)==PR_RDWR) { - if (flag) strcat(bytes, ","); - strcat(bytes, "readWrite"); - flag = JS_TRUE; - } - if ((file->mode&PR_APPEND)==PR_APPEND) { - if (flag) strcat(bytes, ","); - strcat(bytes, "append"); - flag = JS_TRUE; - } - if ((file->mode&PR_CREATE_FILE)==PR_CREATE_FILE) { - if (flag) strcat(bytes, ","); - strcat(bytes, "create"); - flag = JS_TRUE; - } - if ((file->mode&PR_TRUNCATE)==PR_TRUNCATE) { - if (flag) strcat(bytes, ","); - strcat(bytes, "replace"); - flag = JS_TRUE; - } - if (file->hasAutoflush) { - if (flag) strcat(bytes, ","); - strcat(bytes, "hasAutoFlush"); - flag = JS_TRUE; - } - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, bytes)); - JS_free(cx, bytes); - 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; - - str = JS_ValueToString(cx, id); - if (!str) - return JS_FALSE; - - prop_name = JS_GetStringBytes(str); - - /* 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)){ - bytes = js_combinePath(cx, file->path, prop_name); - *vp = OBJECT_TO_JSVAL(js_NewFileObject(cx, bytes)); - JS_free(cx, bytes); - return JS_TRUE; - } - } - } - } - return JS_TRUE; - -out: - 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: - return JS_FALSE; -} - -/* - File.currentDir = new File("D:\") or File.currentDir = "D:\" -*/ -static JSBool -file_currentDirSetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSFile *file; - - file = JS_GetInstancePrivate(cx, obj, &file_class, NULL); - - /* Look at the rhs and extract a file object from it */ - if (JSVAL_IS_OBJECT(*vp)) { - if (JS_InstanceOf(cx, obj, &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); - return JS_FALSE; - } else { - chdir(file->path); - return JS_TRUE; - } - } else { - return JS_FALSE; - } - } else { - JSObject *rhsObject; - char *path; - - path = JS_GetStringBytes(JS_ValueToString(cx, *vp)); - rhsObject = js_NewFileObject(cx, path); - if (!rhsObject) - return JS_FALSE; - - 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; -} - -/* 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) -{ - 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 ); - - /* 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 deleted file mode 100644 index 741c5bdd0..000000000 --- a/src/dom/js/jsfile.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- 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); - -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/jsfile.msg b/src/dom/js/jsfile.msg deleted file mode 100644 index 137b35d87..000000000 --- a/src/dom/js/jsfile.msg +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- 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 jsfile.c. See js.msg for format specification. -*/ - -MSG_DEF(JSFILEMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "") -MSG_DEF(JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR, 1, 0, JSEXN_NONE, "File constructor is undefined") -MSG_DEF(JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR, 2, 0, JSEXN_NONE, "File.currentDir is undefined") -MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR, 3, 1, JSEXN_NONE, "The first argument {0} to file.open must be a string") -MSG_DEF(JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR, 4, 0, JSEXN_NONE, "The second argument to file.open must be a string") -MSG_DEF(JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR, 5, 1, JSEXN_NONE, "Cannot copy file {0} open for writing") -MSG_DEF(JSFILEMSG_CANNOT_ACCESS_FILE_INFO_ERROR, 6, 1, JSEXN_NONE, "Cannot access file information for {0}") -MSG_DEF(JSFILEMSG_COPY_READ_ERROR, 7, 1, JSEXN_NONE, "An error occured while attempting to read a file {0} to copy") -MSG_DEF(JSFILEMSG_COPY_WRITE_ERROR, 8, 1, JSEXN_NONE, "An error occured while attempting to copy into file {0}") -MSG_DEF(JSFILEMSG_EXPECTS_ONE_ARG_ERROR, 9, 0, JSEXN_NONE, "Operation {0} expects one argument, not {1}") -MSG_DEF(JSFILEMSG_CANNOT_FLUSH_CLOSE_FILE_ERROR, 10, 1, JSEXN_NONE, "Cannot flush closed file {0}") -MSG_DEF(JSFILEMSG_CANNOT_OPEN_WRITING_ERROR, 11, 1, JSEXN_NONE, "Cannot open file {0} for writing") -MSG_DEF(JSFILEMSG_WRITEALL_EXPECTS_ONE_ARG_ERROR, 12, 0, JSEXN_NONE, "writeAll expects one argument") -MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR, 13, 0, JSEXN_NONE, "writeAll expects an array as an argument") -MSG_DEF(JSFILEMSG_UNUSED0, 14, 0, JSEXN_NONE, "Unused error message slot") -MSG_DEF(JSFILEMSG_CANNOT_OPEN_FILE_ERROR, 15, 1, JSEXN_NONE, "Cannot open file {0}") -MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR, 16, 1, JSEXN_NONE, "The argument to the File constructor {0} must be a string") -MSG_DEF(JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED, 17, 0, JSEXN_NONE, "Bidirectional pipes are not supported") -MSG_DEF(JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES, 18, 2, JSEXN_NONE, "The opening mode you have chosen {0} is not supported by the pipe you are trying to open: {1}") -MSG_DEF(JSFILEMSG_OPEN_FAILED, 19, 1, JSEXN_NONE, "open on file {0} failed") -MSG_DEF(JSFILEMSG_CLOSE_FAILED, 20, 1, JSEXN_NONE, "close on file {0} failed") -MSG_DEF(JSFILEMSG_PCLOSE_FAILED, 21, 1, JSEXN_NONE, "pclose on file {0} failed") -MSG_DEF(JSFILEMSG_REMOVE_FAILED, 22, 1, JSEXN_NONE, "remove on file {0} failed") -MSG_DEF(JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, 23, 1, JSEXN_NONE, "Cannot access file status for {0}") -MSG_DEF(JSFILEMSG_RENAME_FAILED, 24, 2, JSEXN_NONE, "Cannot rename {0} to {1}") -MSG_DEF(JSFILEMSG_WRITE_FAILED, 25, 1, JSEXN_NONE, "Write failed on file {0}") -MSG_DEF(JSFILEMSG_READ_FAILED, 26, 1, JSEXN_NONE, "Read failed on file {0}") -MSG_DEF(JSFILEMSG_SKIP_FAILED, 27, 1, JSEXN_NONE, "Skip failed on file {0}") -MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, 28, 1, JSEXN_NONE, "The first argument to file.list must be a function or a regex") -MSG_DEF(JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE, 29, 1, JSEXN_NONE, "{0} must be a directory, cannot do list") -MSG_DEF(JSFILEMSG_NATIVE_OPERATION_IS_NOT_SUPPORTED, 30, 2, JSEXN_NONE, "Native operation {0} is not supported on {1}") -MSG_DEF(JSFILEMSG_CANNOT_SET_PRIVATE_FILE, 31, 1, JSEXN_NONE, "Cannot set private data for file {0}") -MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, 32, 2, JSEXN_NONE, "First argument to {0} must be a number, not {1}") -MSG_DEF(JSFILEMSG_CANNOT_WRITE, 33, 1, JSEXN_NONE, "Cannot write to {0}, file mode is different") -MSG_DEF(JSFILEMSG_CANNOT_READ, 34, 1, JSEXN_NONE, "Cannot read from {0}, file mode is different") -MSG_DEF(JSFILEMSG_CANNOT_FLUSH, 35, 1, JSEXN_NONE, "Flush failed on {0}") -MSG_DEF(JSFILEMSG_OP_FAILED, 36, 1, JSEXN_NONE, "File operation {0} failed") -MSG_DEF(JSFILEMSG_FILE_MUST_BE_OPEN, 37, 1, JSEXN_NONE, "File must be open for {0}") -MSG_DEF(JSFILEMSG_FILE_MUST_BE_CLOSED, 38, 1, JSEXN_NONE, "File must be closed for {0}") -MSG_DEF(JSFILEMSG_NO_RANDOM_ACCESS, 39, 1, JSEXN_NONE, "File {0} doesn't allow random access") -MSG_DEF(JSFILEMSG_OBJECT_CREATION_FAILED, 40, 1, JSEXN_NONE, "Couldn't create {0}") -MSG_DEF(JSFILEMSG_CANNOT_OPEN_DIR, 41, 1, JSEXN_NONE, "Couldn't open directory {0}") -MSG_DEF(JSFILEMSG_CANNOT_REPORT_POSITION, 42, 1, JSEXN_NONE, "Couldn't report position for {0}") -MSG_DEF(JSFILEMSG_CANNOT_SET_POSITION, 43, 1, JSEXN_NONE, "Couldn't set position for {0}") -MSG_DEF(JSFILEMSG_INIT_FAILED, 44, 0, JSEXN_NONE, "File class initialization failed") - - diff --git a/src/dom/js/jsfun.c b/src/dom/js/jsfun.c deleted file mode 100644 index 68372e129..000000000 --- a/src/dom/js/jsfun.c +++ /dev/null @@ -1,2258 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=78: - * - * ***** 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 -#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, - ATOM_TO_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 = fp->argc; - 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 (fp->argc <= 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, - ATOM_TO_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 (JSID_IS_INT(id)) { - slot = (uintN) JSID_TO_INT(id); - if (slot < fp->argc) { - if (fp->argsobj && ArgWasDeleted(cx, fp, slot)) - return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); - *vp = fp->argv[slot]; - } else { - /* - * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share - * storage between the formal parameter and arguments[k] for all - * k >= fp->argc && k < fp->fun->nargs. For example, in - * - * function f(x) { x = 42; return arguments[0]; } - * f(); - * - * the call to f should return undefined, not 42. If fp->argsobj - * is null at this point, as it would be in the example, return - * undefined in *vp. - */ - if (fp->argsobj) - return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); - } - } else { - if (id == ATOM_TO_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; - - /* Skip eval and debugger frames. */ - while (fp->flags & JSFRAME_SPECIAL) - fp = fp->down; - - /* Create an arguments object for fp only if it lacks one. */ - 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 (fp->argc > 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, ATOM_TO_JSID(rt->atomState.calleeAtom), - &rval); - ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom), - &rval); - ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom), - &rval); - ok &= js_SetProperty(cx, argsobj, ATOM_TO_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); - - slot = JSVAL_TO_INT(id); - switch (slot) { - case ARGS_CALLEE: - case ARGS_LENGTH: - SET_OVERRIDE_BIT(fp, slot); - break; - - default: - if ((uintN)slot < fp->argc && !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); - - 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 < fp->argc && !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); - - slot = JSVAL_TO_INT(id); - switch (slot) { - case ARGS_CALLEE: - case ARGS_LENGTH: - SET_OVERRIDE_BIT(fp, slot); - break; - - default: - if (fp->fun->interpreted && - (uintN)slot < fp->argc && - !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); - - if (JSVAL_IS_INT(id)) { - slot = JSVAL_TO_INT(id); - if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) { - /* XXX ECMA specs DontEnum, contrary to other array-like objects */ - if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id), - fp->argv[slot], - args_getProperty, args_setProperty, - JS_VERSION_IS_ECMA(cx) - ? 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, ATOM_TO_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, argc; - - fp = (JSStackFrame *) - JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); - if (!fp) - return JS_TRUE; - JS_ASSERT(fp->argsobj); - - /* - * 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, - ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), - &pobj, &prop)) { - return JS_FALSE; - } - if (prop) - OBJ_DROP_PROPERTY(cx, pobj, prop); - - if (!js_LookupProperty(cx, obj, - ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), - &pobj, &prop)) { - return JS_FALSE; - } - if (prop) - OBJ_DROP_PROPERTY(cx, pobj, prop); - - argc = fp->argc; - for (slot = 0; slot < argc; slot++) { - if (!js_LookupProperty(cx, obj, INT_TO_JSID((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 = ATOM_TO_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, *pobj; - JSScope *scope; - JSScopeProperty *sprop, *cprop; - JSPropertyOp getter; - jsval *vec; - JSAtom *atom; - 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 by looking up the unhidden atom for sprop->id. */ - JS_ASSERT(JSID_IS_ATOM(sprop->id)); - atom = JSID_TO_ATOM(sprop->id); - JS_ASSERT(atom->flags & ATOM_HIDDEN); - atom = atom->entry.value; - - if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop)) - return JS_FALSE; - - /* - * If we found the property in a different object, don't try sticking - * it into wrong slots vector. This can occur because we have a mutable - * __proto__ slot, and cloned function objects rely on their __proto__ - * to delegate to the object that contains the var and arg properties. - */ - if (!prop || pobj != obj) { - if (prop) - OBJ_DROP_PROPERTY(cx, pobj, prop); - continue; - } - cprop = (JSScopeProperty *)prop; - LOCKED_OBJ_SET_SLOT(obj, cprop->slot, vec[(uint16) 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; - JSProperty *prop; - JSScopeProperty *sprop; - 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; - JS_ASSERT((JSFunction *) JS_GetPrivate(cx, funobj) == fp->fun); - - str = JSVAL_TO_STRING(id); - atom = js_AtomizeString(cx, str, 0); - if (!atom) - return JS_FALSE; - if (!js_LookupHiddenProperty(cx, funobj, ATOM_TO_JSID(atom), &obj2, &prop)) - return JS_FALSE; - - if (prop) { - if (!OBJ_IS_NATIVE(obj2)) { - OBJ_DROP_PROPERTY(cx, obj2, prop); - return JS_TRUE; - } - - sprop = (JSScopeProperty *) prop; - getter = sprop->getter; - attrs = sprop->attrs & ~JSPROP_SHARED; - slot = (uintN) sprop->shortid; - OBJ_DROP_PROPERTY(cx, obj2, prop); - - /* Ensure we found an arg or var property for the same function. */ - if ((sprop->flags & SPROP_IS_HIDDEN) && - (obj2 == funobj || - (JSFunction *) JS_GetPrivate(cx, obj2) == fp->fun)) { - if (getter == js_GetArgument) { - vp = fp->argv; - nslots = JS_MAX(fp->argc, fp->fun->nargs); - getter = setter = NULL; - } else { - JS_ASSERT(getter == js_GetLocalVariable); - 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, ATOM_TO_JSID(atom), 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 */ - -/* - * ECMA-262 specifies that length is a property of function object instances, - * but we can avoid that space cost by delegating to a prototype property that - * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes - * a fresh length value based on the arity of the individual function object's - * private data. - * - * The extensions below other than length, i.e., the ones not in ECMA-262, - * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility - * with ECMA we must allow a delegating object to override them. - */ -#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED) - -static JSPropertySpec function_props[] = { - {js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT, 0,0}, - {js_arity_str, FUN_ARITY, JSPROP_PERMANENT, 0,0}, - {js_caller_str, FUN_CALLER, JSPROP_PERMANENT, 0,0}, - {js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, 0,0}, - {js_name_str, FUN_NAME, JSPROP_PERMANENT, 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 (!JSVAL_IS_INT(id)) - return JS_TRUE; - slot = JSVAL_TO_INT(id); - - /* - * Loop because getter and setter can be delegated from another class, - * but loop only for ARGS_LENGTH because we must pretend that f.length - * is in each function instance f, per ECMA-262, instead of only in the - * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED - * to make it appear so). - * - * This code couples tightly to the attributes for the function_props[] - * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper. - * - * It's important to allow delegating objects, even though they inherit - * this getter (fun_getProperty), to override arguments, arity, caller, - * and name. If we didn't return early for slot != ARGS_LENGTH, we would - * clobber *vp with the native property value, instead of letting script - * override that value in delegating objects. - * - * Note how that clobbering is what simulates JSPROP_READONLY for all of - * the non-standard properties when the directly addressed object (obj) - * is a function object (i.e., when this loop does not iterate). - */ - while (!(fun = (JSFunction *) - JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { - if (slot != ARGS_LENGTH) - return JS_TRUE; - obj = OBJ_GET_PROTO(cx, obj); - if (!obj) - 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 (!JS_VERSION_IS_ECMA(cx)) - *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) - *vp = fp->argv[slot]; - break; - } - - return JS_TRUE; -} - -static JSBool -fun_enumerate(JSContext *cx, JSObject *obj) -{ - jsid prototypeId; - JSObject *pobj; - JSProperty *prop; - - prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); - if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop)) - return JS_FALSE; - if (prop) - OBJ_DROP_PROPERTY(cx, pobj, prop); - 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, ATOM_TO_JSID(prototypeAtom), - &pval)) { - return JS_FALSE; - } - if (!JSVAL_IS_PRIMITIVE(pval)) { - /* - * We are about to allocate a new object, so hack the newborn - * root until then to protect pval in case it is figuratively - * up in the air, with no strong refs protecting it. - */ - cx->newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(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 (15.3.5.2) says that constructor.prototype is 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_ENUMERATE | 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; - - /* Null-check required since the parser sets interpreted very early. */ - if (fun->interpreted && fun->u.script) - js_DestroyScript(cx, fun->u.script); -} - -#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; - JSTempValueRooter tvr; - uint32 flagsword; /* originally only flags was JS_XDRUint8'd */ - char *propname; - JSScopeProperty *sprop; - uint32 userid; /* NB: holds a signed int-tagged jsval */ - JSAtom *atom; - uintN i, n, dupflag; - uint32 type; - JSBool ok; -#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; - if (!fun->interpreted) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_NOT_SCRIPTED_FUNCTION, - JS_GetFunctionName(fun)); - return JS_FALSE; - } - atomstr = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; - flagsword = ((uint32)fun->nregexps << 16) | fun->flags; - } else { - fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL); - if (!fun) - return JS_FALSE; - atomstr = NULL; - } - - /* From here on, control flow must flow through label out. */ - JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(fun->object), &tvr); - ok = JS_TRUE; - - if (!JS_XDRStringOrNull(xdr, &atomstr) || - !JS_XDRUint16(xdr, &fun->nargs) || - !JS_XDRUint16(xdr, &fun->extra) || - !JS_XDRUint16(xdr, &fun->nvars) || - !JS_XDRUint32(xdr, &flagsword)) { - goto bad; - } - - /* 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); - goto bad; - } - } - 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(JSID_TO_ATOM(sprop->id))); - if (!propname || - !JS_XDRUint32(xdr, &type) || - !JS_XDRUint32(xdr, &userid) || - !JS_XDRCString(xdr, &propname)) { - if (mark) - JS_ARENA_RELEASE(&cx->tempPool, mark); - goto bad; - } - } - if (mark) - JS_ARENA_RELEASE(&cx->tempPool, mark); - } else { - JSPropertyOp getter, setter; - - for (i = n; i != 0; i--) { - uintN attrs = JSPROP_PERMANENT; - - if (!JS_XDRUint32(xdr, &type) || - !JS_XDRUint32(xdr, &userid) || - !JS_XDRCString(xdr, &propname)) { - goto bad; - } - 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) - goto bad; - - /* Flag duplicate argument if atom is bound in fun->object. */ - dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object), - ATOM_TO_JSID(atom)) - ? SPROP_IS_DUPLICATE - : 0; - - if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom), - getter, setter, SPROP_INVALID_SLOT, - attrs | JSPROP_SHARED, - dupflag | SPROP_HAS_SHORTID, - JSVAL_TO_INT(userid))) { - goto bad; - } - } - } - } - - if (!js_XDRScript(xdr, &fun->u.script, NULL)) - goto bad; - - if (xdr->mode == JSXDR_DECODE) { - fun->interpreted = JS_TRUE; - fun->flags = (uint8) flagsword; - fun->nregexps = (uint16) (flagsword >> 16); - - *objp = fun->object; - if (atomstr) { - /* XXX only if this was a top-level function! */ - fun->atom = js_AtomizeString(cx, atomstr, 0); - if (!fun->atom) - goto bad; - } - - js_CallNewScriptHook(cx, fun->u.script, fun); - } - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; - -bad: - ok = JS_FALSE; - goto out; -} - -#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; - JSString *str; - - if (!OBJ_GET_PROPERTY(cx, obj, - ATOM_TO_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; - } - - return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp); -} - -#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) { - JS_MarkGCThing(cx, fun, js_private_str, arg); - if (fun->atom) - GC_MARK_ATOM(cx, fun->atom, arg); - if (fun->interpreted && fun->u.script) - js_MarkScript(cx, fun->u.script, arg); - } - return 0; -} - -static uint32 -fun_reserveSlots(JSContext *cx, JSObject *obj) -{ - JSFunction *fun; - - fun = (JSFunction *) JS_GetPrivate(cx, obj); - return fun ? fun->nregexps : 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. - */ -JS_FRIEND_DATA(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, - fun_enumerate, (JSResolveOp)fun_resolve, - fun_convert, fun_finalize, - NULL, NULL, - NULL, NULL, - fun_xdrObject, fun_hasInstance, - fun_mark, fun_reserveSlots -}; - -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; - } - argv[-1] = fval; - } - 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 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; - JSString *str; - 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)) { - str = JS_ValueToString(cx, fval); - if (str) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_INCOMPATIBLE_PROTO, - js_Function_str, call_str, - JS_GetStringBytes(str)); - } - return JS_FALSE; - } - - if (argc == 0) { - /* Call fun with its global object as the 'this' param if no args. */ - obj = NULL; - } 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; - JSString *str; - JSObject *aobj; - jsuint length; - void *mark; - uintN i; - JSBool ok; - JSStackFrame *fp; - - if (argc == 0) { - /* Will get globalObject as 'this' and no other arguments. */ - 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)) { - str = JS_ValueToString(cx, fval); - if (str) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_INCOMPATIBLE_PROTO, - js_Function_str, "apply", - JS_GetStringBytes(str)); - } - 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 - {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_ISIDSTART(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; - JSProperty *prop; - JSScopeProperty *sprop; - JSString *str, *arg; - void *mark; - JSTokenStream *ts; - JSPrincipals *principals; - jschar *collected_args, *cp; - size_t arg_length, args_length, old_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, - JS_VERSION_IS_ECMA(cx) - ? 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->u.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; - } - - /* Belt-and-braces: check that the caller has access to parent. */ - if (!js_CheckPrincipalsAccess(cx, parent, principals, js_Function_str)) - return JS_FALSE; - - 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); - - /* - * Check for overflow. The < test works because the maximum - * JSString length fits in 2 fewer bits than size_t has. - */ - old_args_length = args_length; - args_length = old_args_length + JSSTRING_LENGTH(arg); - if (args_length < old_args_length) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - } - - /* Add 1 for each joining comma and check for overflow (two ways). */ - old_args_length = args_length; - args_length = old_args_length + n - 1; - if (args_length < old_args_length || - args_length >= ~(size_t)0 / sizeof(jschar)) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - /* - * 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) { - JS_ReportOutOfMemory(cx); - 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_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), - &obj2, &prop)) { - goto bad_formal; - } - sprop = (JSScopeProperty *) prop; - 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, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_DUPLICATE_FORMAL, - name); - - dupflag = SPROP_IS_DUPLICATE; - } - OBJ_DROP_PROPERTY(cx, obj2, prop); - if (!ok) - goto bad_formal; - sprop = NULL; - } - if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom), - js_GetArgument, js_SetArgument, - SPROP_INVALID_SLOT, - JSPROP_PERMANENT | JSPROP_SHARED, - dupflag | SPROP_HAS_SHORTID, - fun->nargs)) { - goto bad_formal; - } - if (fun->nargs == JS_BITMASK(16)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TOO_MANY_FUN_ARGS); - goto bad; - } - 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); - -bad: - /* - * 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->u.script = js_NewScript(cx, 0, 0, 0); - if (!fun->u.script) - goto bad; - fun->interpreted = JS_TRUE; - return proto; - -bad: - cx->newborn[GCX_OBJECT] = NULL; - return NULL; -} - -#if JS_HAS_CALL_OBJECT -JSObject * -js_InitCallClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto; - - proto = JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0, - call_props, NULL, NULL, NULL); - if (!proto) - return NULL; - - /* - * Null Call.prototype's proto slot so that Object.prototype.* does not - * pollute the scope of heavyweight functions. - */ - OBJ_SET_PROTO(cx, proto, NULL); - return proto; -} -#endif - -JSFunction * -js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, - uintN flags, JSObject *parent, JSAtom *atom) -{ - JSFunction *fun; - JSTempValueRooter tvr; - - /* 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) - return NULL; - } - - /* Protect fun from any potential last-ditch GCs. */ - JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(funobj), &tvr); - - /* - * Allocate fun after allocating funobj so slot allocation in js_NewObject - * does not wipe out fun from cx->newborn[GCX_PRIVATE]. - */ - fun = (JSFunction *) js_NewGCThing(cx, GCX_PRIVATE, sizeof(JSFunction)); - if (!fun) - goto out; - - /* Initialize all function members. */ - fun->nrefs = 0; - fun->object = NULL; - fun->u.native = native; - fun->nargs = nargs; - fun->extra = 0; - fun->nvars = 0; - fun->flags = flags & JSFUN_FLAGS_MASK; - fun->interpreted = JS_FALSE; - fun->nregexps = 0; - 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; - fun = NULL; - } - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - 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, ATOM_TO_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); -} - -JSObject * -js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags) -{ - JSFunction *fun; - JSObject *funobj; - JSStackFrame *caller; - JSPrincipals *principals; - - if (JSVAL_IS_FUNCTION(cx, *vp)) - return JSVAL_TO_OBJECT(*vp); - - fun = js_ValueToFunction(cx, vp, flags); - if (!fun) - return NULL; - funobj = fun->object; - *vp = OBJECT_TO_JSVAL(funobj); - - caller = JS_GetScriptedCaller(cx, cx->fp); - if (caller) { - principals = caller->script->principals; - } else { - /* No scripted caller, don't allow access. */ - principals = NULL; - } - - /* - * FIXME: Reparameterize so we don't call js_AtomToPrintableString unless - * there is an error (bug 324694). - */ - if (!js_CheckPrincipalsAccess(cx, funobj, principals, - fun->atom - ? js_AtomToPrintableString(cx, fun->atom) - : js_anonymous_str)) { - return NULL; - } - return funobj; -} - -JSObject * -js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags) -{ - JSObject *callable; - - callable = JSVAL_IS_PRIMITIVE(*vp) ? NULL : JSVAL_TO_OBJECT(*vp); - if (callable && - ((callable->map->ops == &js_ObjectOps) - ? OBJ_GET_CLASS(cx, callable)->call - : callable->map->ops->call)) { - *vp = OBJECT_TO_JSVAL(callable); - } else { - callable = js_ValueToFunctionObject(cx, vp, flags); - } - return callable; -} - -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 deleted file mode 100644 index 25aa10320..000000000 --- a/src/dom/js/jsfun.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- 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 */ - union { - JSNative native; /* native method pointer or null */ - JSScript *script; /* interpreted bytecode descriptor or null */ - } u; - 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 */ - JSPackedBool interpreted; /* use u.script if true, u.native if false */ - uint16 nregexps; /* number of regular expressions literals */ - uint16 spare; /* reserved for future use */ - JSAtom *atom; /* name for diagnostics and decompiling */ - JSClass *clasp; /* if non-null, constructor for this class */ -}; - -#define FUN_NATIVE(fun) ((fun)->interpreted ? NULL : (fun)->u.native) -#define FUN_SCRIPT(fun) ((fun)->interpreted ? (fun)->u.script : NULL) - -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_PRIMITIVE(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 JSObject * -js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags); - -extern JSObject * -js_ValueToCallableObject(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 deleted file mode 100644 index 2383240c7..000000000 --- a/src/dom/js/jsgc.c +++ /dev/null @@ -1,1989 +0,0 @@ -/* -*- 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 /* for free, called by JS_ARENA_DESTROY */ -#include /* 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" - -#if JS_HAS_XML_SUPPORT -#include "jsxml.h" -#endif - -/* - * 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) - -/* - * 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) - -/* - * Given a jsuword page pointer p and a thing size n, return the address of - * the first thing in p. We know that any n not a power of two packs from - * the end of the page leaving at least enough room for one JSGCPageInfo, but - * not for another thing, at the front of the page (JS_ASSERTs below insist - * on this). - * - * This works because all allocations are a multiple of sizeof(JSGCThing) == - * sizeof(JSGCPageInfo) in size. - */ -#define FIRST_THING(p,n) (((n) & ((n) - 1)) \ - ? (p) + (uint32)(GC_PAGE_SIZE % (n)) \ - : (p) + (n)) - -static JSGCThing * -gc_new_arena(JSArenaPool *pool, size_t nbytes) -{ - uint8 *flagp, *split, *pagep, *limit; - JSArena *a; - jsuword p; - 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. */ - p = FIRST_THING_PAGE(a); - split = pagep = (uint8 *) p; - a->avail = FIRST_THING(p, nbytes); - JS_ASSERT(a->avail >= p + sizeof(JSGCPageInfo)); - thing = (JSGCThing *) a->avail; - JS_ArenaCountAllocation(pool, a->avail - p); - a->avail += nbytes; - - /* 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_LOCK | GCF_FINAL)); -} - -typedef void (*GCFinalizeOp)(JSContext *cx, JSGCThing *thing); - -#ifndef DEBUG -# define js_FinalizeDouble NULL -#endif - -#if !JS_HAS_XML_SUPPORT -# define js_FinalizeXMLNamespace NULL -# define js_FinalizeXMLQName NULL -# define js_FinalizeXML NULL -#endif - -static GCFinalizeOp gc_finalizers[GCX_NTYPES] = { - (GCFinalizeOp) js_FinalizeObject, /* GCX_OBJECT */ - (GCFinalizeOp) js_FinalizeString, /* GCX_STRING */ - (GCFinalizeOp) js_FinalizeDouble, /* GCX_DOUBLE */ - (GCFinalizeOp) js_FinalizeString, /* GCX_MUTABLE_STRING */ - NULL, /* GCX_PRIVATE */ - (GCFinalizeOp) js_FinalizeXMLNamespace, /* GCX_NAMESPACE */ - (GCFinalizeOp) js_FinalizeXMLQName, /* GCX_QNAME */ - (GCFinalizeOp) js_FinalizeXML, /* GCX_XML */ - NULL, /* GCX_EXTERNAL_STRING */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -#ifdef GC_MARK_DEBUG -static const char newborn_external_string[] = "newborn external string"; - -static const char *gc_typenames[GCX_NTYPES] = { - "newborn object", - "newborn string", - "newborn double", - "newborn mutable string", - "newborn private", - "newborn Namespace", - "newborn QName", - "newborn XML", - newborn_external_string, - newborn_external_string, - newborn_external_string, - newborn_external_string, - newborn_external_string, - newborn_external_string, - newborn_external_string, - newborn_external_string -}; -#endif - -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) -{ - uintN i; - - 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)); - - for (i = 0; i < GC_NUM_FREELISTS; i++) - JS_InitArenaPool(&rt->gcArenaPool[i], "gc-arena", GC_ARENA_SIZE, 1); - 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 */ - - /* - * Separate gcMaxMallocBytes from gcMaxBytes but initialize to maxbytes - * for default backward API compatibility. - */ - rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes; - return JS_TRUE; -} - -#ifdef JS_GCMETER -JS_FRIEND_API(void) -js_DumpGCStats(JSRuntime *rt, FILE *fp) -{ - uintN i; - - fprintf(fp, "\nGC allocation statistics:\n"); - -#define UL(x) ((unsigned long)(x)) -#define ULSTAT(x) UL(rt->gcStats.x) - fprintf(fp, " public bytes allocated: %lu\n", UL(rt->gcBytes)); - fprintf(fp, " private bytes allocated: %lu\n", UL(rt->gcPrivateBytes)); - fprintf(fp, " alloc attempts: %lu\n", ULSTAT(alloc)); - for (i = 0; i < GC_NUM_FREELISTS; i++) { - fprintf(fp, " GC freelist %u length: %lu\n", - i, ULSTAT(freelen[i])); - fprintf(fp, " recycles via GC freelist %u: %lu\n", - i, ULSTAT(recycle[i])); - } - fprintf(fp, "allocation retries after GC: %lu\n", ULSTAT(retry)); - fprintf(fp, " allocation failures: %lu\n", ULSTAT(fail)); - fprintf(fp, " things born locked: %lu\n", ULSTAT(lockborn)); - fprintf(fp, " valid lock calls: %lu\n", ULSTAT(lock)); - fprintf(fp, " valid unlock calls: %lu\n", ULSTAT(unlock)); - fprintf(fp, " mark recursion depth: %lu\n", ULSTAT(depth)); - fprintf(fp, " maximum mark recursion: %lu\n", ULSTAT(maxdepth)); - fprintf(fp, " mark C recursion depth: %lu\n", ULSTAT(cdepth)); - fprintf(fp, " maximum mark C recursion: %lu\n", ULSTAT(maxcdepth)); - fprintf(fp, " mark C stack overflows: %lu\n", ULSTAT(dswmark)); - fprintf(fp, " mark DSW recursion depth: %lu\n", ULSTAT(dswdepth)); - fprintf(fp, " maximum mark DSW recursion: %lu\n", ULSTAT(maxdswdepth)); - fprintf(fp, " mark DSW up-tree movement: %lu\n", ULSTAT(dswup)); - fprintf(fp, "DSW up-tree obj->slot steps: %lu\n", ULSTAT(dswupstep)); - fprintf(fp, " maximum GC nesting level: %lu\n", ULSTAT(maxlevel)); - fprintf(fp, "potentially useful GC calls: %lu\n", ULSTAT(poke)); - fprintf(fp, " useless GC calls: %lu\n", ULSTAT(nopoke)); - fprintf(fp, " thing arenas freed so far: %lu\n", ULSTAT(afree)); - fprintf(fp, " stack segments scanned: %lu\n", ULSTAT(stackseg)); - fprintf(fp, "stack segment slots scanned: %lu\n", ULSTAT(segslots)); -#undef UL -#undef US - -#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) -{ - uintN i; - -#ifdef JS_ARENAMETER - JS_DumpArenaStats(stdout); -#endif -#ifdef JS_GCMETER - js_DumpGCStats(rt, stdout); -#endif - for (i = 0; i < GC_NUM_FREELISTS; i++) { - JS_FinishArenaPool(&rt->gcArenaPool[i]); - rt->gcFreeList[i] = NULL; - } - 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; - } -} - -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; -} - -#ifdef DEBUG_brendan -#define NGCHIST 64 - -static struct GCHist { - JSBool lastDitch; - JSGCThing *freeList; -} gchist[NGCHIST]; - -unsigned gchpos; -#endif - -void * -js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) -{ - JSBool tried_gc; - JSRuntime *rt; - size_t nflags; - uintN i; - JSGCThing *thing, **flp; - uint8 *flagp; - JSLocalRootStack *lrs; - uint32 *bytesptr; - - rt = cx->runtime; - JS_LOCK_GC(rt); - JS_ASSERT(!rt->gcRunning); - if (rt->gcRunning) { - METER(rt->gcStats.finalfail++); - JS_UNLOCK_GC(rt); - return NULL; - } - -#ifdef TOO_MUCH_GC -#ifdef WAY_TOO_MUCH_GC - rt->gcPoke = JS_TRUE; -#endif - js_GC(cx, GC_KEEP_ATOMS | GC_ALREADY_LOCKED); - tried_gc = JS_TRUE; -#else - tried_gc = JS_FALSE; -#endif - - METER(rt->gcStats.alloc++); - nbytes = JS_ROUNDUP(nbytes, sizeof(JSGCThing)); - nflags = nbytes / sizeof(JSGCThing); - i = GC_FREELIST_INDEX(nbytes); - flp = &rt->gcFreeList[i]; - -retry: - thing = *flp; - if (thing) { - *flp = thing->next; - flagp = thing->flagp; - METER(rt->gcStats.freelen[i]--); - METER(rt->gcStats.recycle[i]++); - } else { - if (rt->gcBytes < rt->gcMaxBytes && - (tried_gc || rt->gcMallocBytes < rt->gcMaxMallocBytes)) - { - /* - * 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[i]; - JSArena *a = pool->current; - jsuword p = a->avail; - jsuword q = p + nbytes; - - if (q > (a->limit & ~GC_PAGE_MASK)) { - thing = gc_new_arena(pool, nbytes); - } else { - if ((p & GC_PAGE_MASK) == 0) { - /* Beware, p points to a JSGCPageInfo record! */ - p = FIRST_THING(p, nbytes); - q = p + nbytes; - JS_ArenaCountAllocation(pool, p & GC_PAGE_MASK); - } - a->avail = q; - thing = (JSGCThing *)p; - } - JS_ArenaCountAllocation(pool, nbytes); - } - - /* - * 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; - } - goto fail; - } - - /* Find the flags pointer given thing's address. */ - flagp = js_GetGCThingFlags(thing); - } - - lrs = cx->localRootStack; - if (lrs) { - /* - * If we're in a local root scope, don't set cx->newborn[type] at all, - * to avoid entraining garbage from it for an unbounded amount of time - * on this context. A caller will leave the local root scope and pop - * this reference, allowing thing to be GC'd if it has no other refs. - * See JS_EnterLocalRootScope and related APIs. - */ - if (js_PushLocalRoot(cx, lrs, (jsval) thing) < 0) { - /* - * When we fail for a thing allocated through the tail of - * the last arena, thing's flag byte is not initialized. So - * to prevent GC accessing the uninitialized flags during - * the finalization, we always mark the thing as final. See - * bug 337407. - */ - *flagp = GCF_FINAL; - goto fail; - } - } else { - /* - * No local root scope, so we're stuck with the old, fragile model of - * depending on a pigeon-hole newborn per type per context. - */ - cx->newborn[flags & GCF_TYPEMASK] = thing; - } - - /* We can't fail now, so update flags and rt->gc{,Private}Bytes. */ - *flagp = (uint8)flags; - bytesptr = ((flags & GCF_TYPEMASK) == GCX_PRIVATE) - ? &rt->gcPrivateBytes - : &rt->gcBytes; - *bytesptr += nbytes + nflags; - - /* - * 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; -#ifdef DEBUG_brendan - gchist[gchpos].lastDitch = tried_gc; - gchist[gchpos].freeList = *flp; - if (++gchpos == NGCHIST) - gchpos = 0; -#endif - METER(if (flags & GCF_LOCK) rt->gcStats.lockborn++); - JS_UNLOCK_GC(rt); - return thing; - -fail: - METER(rt->gcStats.fail++); - JS_UNLOCK_GC(rt); - JS_ReportOutOfMemory(cx); - return NULL; -} - -JSBool -js_LockGCThing(JSContext *cx, void *thing) -{ - JSBool ok = js_LockGCThingRT(cx->runtime, thing); - if (!ok) - JS_ReportOutOfMemory(cx); - return ok; -} - -/* - * Deep GC-things can't be locked just by setting the GCF_LOCK bit, because - * their descendants must be marked by the GC. To find them during the mark - * phase, they are added to rt->gcLocksHash, which is created lazily. - * - * NB: we depend on the order of GC-thing type indexes here! - */ -#define GC_TYPE_IS_STRING(t) ((t) == GCX_STRING || \ - (t) >= GCX_EXTERNAL_STRING) -#define GC_TYPE_IS_XML(t) ((unsigned)((t) - GCX_NAMESPACE) <= \ - (unsigned)(GCX_XML - GCX_NAMESPACE)) -#define GC_TYPE_IS_DEEP(t) ((t) == GCX_OBJECT || GC_TYPE_IS_XML(t)) - -#define IS_DEEP_STRING(t,o) (GC_TYPE_IS_STRING(t) && \ - JSSTRING_IS_DEPENDENT((JSString *)(o))) - -#define GC_THING_IS_DEEP(t,o) (GC_TYPE_IS_DEEP(t) || IS_DEEP_STRING(t, o)) - -JSBool -js_LockGCThingRT(JSRuntime *rt, void *thing) -{ - JSBool ok, deep; - uint8 *flagp, flags, lock, type; - JSGCLockHashEntry *lhe; - - ok = JS_TRUE; - if (!thing) - return ok; - - flagp = js_GetGCThingFlags(thing); - - JS_LOCK_GC(rt); - flags = *flagp; - lock = (flags & GCF_LOCK); - type = (flags & GCF_TYPEMASK); - deep = GC_THING_IS_DEEP(type, thing); - - /* - * Avoid adding a rt->gcLocksHash entry for shallow things until someone - * nests a lock -- then start such an entry with a count of 2, not 1. - */ - if (lock || deep) { - if (!rt->gcLocksHash) { - rt->gcLocksHash = - JS_NewDHashTable(JS_DHashGetStubOps(), NULL, - sizeof(JSGCLockHashEntry), - GC_ROOTS_SIZE); - if (!rt->gcLocksHash) { - ok = JS_FALSE; - goto done; - } - } else if (lock == 0) { -#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) { - ok = JS_FALSE; - goto done; - } - if (!lhe->thing) { - lhe->thing = thing; - lhe->count = deep ? 1 : 2; - } else { - JS_ASSERT(lhe->count >= 1); - lhe->count++; - } - } - - *flagp = (uint8)(flags | GCF_LOCK); - METER(rt->gcStats.lock++); - ok = JS_TRUE; -done: - JS_UNLOCK_GC(rt); - return ok; -} - -JSBool -js_UnlockGCThingRT(JSRuntime *rt, void *thing) -{ - uint8 *flagp, flags; - JSGCLockHashEntry *lhe; - - if (!thing) - return JS_TRUE; - - flagp = js_GetGCThingFlags(thing); - JS_LOCK_GC(rt); - flags = *flagp; - - if (flags & GCF_LOCK) { - if (!rt->gcLocksHash || - (lhe = (JSGCLockHashEntry *) - JS_DHashTableOperate(rt->gcLocksHash, thing, - JS_DHASH_LOOKUP), - JS_DHASH_ENTRY_IS_FREE(&lhe->hdr))) { - /* Shallow GC-thing with an implicit lock count of 1. */ - JS_ASSERT(!GC_THING_IS_DEEP(flags & GCF_TYPEMASK, thing)); - } else { - /* Basis or nested unlock of a deep thing, or nested of shallow. */ - if (--lhe->count != 0) - goto out; - JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_REMOVE); - } - *flagp = (uint8)(flags & ~GCF_LOCK); - } - - rt->gcPoke = JS_TRUE; -out: - METER(rt->gcStats.unlock++); - JS_UNLOCK_GC(rt); - return JS_TRUE; -} - -#ifdef GC_MARK_DEBUG - -#include -#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) { - uint8 nextFlags = *js_GetGCThingFlags(next->thing); - if ((nextFlags & GCF_TYPEMASK) == GCX_OBJECT) { - path = JS_sprintf_append(path, "%s(%s @ 0x%08p).", - next->name, - gc_object_class_name(next->thing), - (JSObject*)next->thing); - } else { - 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; - } -#if JS_HAS_XML_SUPPORT - case GCX_NAMESPACE: - { - JSXMLNamespace *ns = (JSXMLNamespace *)thing; - fprintf(fp, "namespace %s:%s", - JS_GetStringBytes(ns->prefix), JS_GetStringBytes(ns->uri)); - break; - } - case GCX_QNAME: - { - JSXMLQName *qn = (JSXMLQName *)thing; - fprintf(fp, "qname %s(%s):%s", - JS_GetStringBytes(qn->prefix), JS_GetStringBytes(qn->uri), - JS_GetStringBytes(qn->localName)); - break; - } - case GCX_XML: - { - extern const char *js_xml_class_str[]; - JSXML *xml = (JSXML *)thing; - fprintf(fp, "xml %8p %s", xml, js_xml_class_str[xml->xml_class]); - break; - } -#endif - case GCX_DOUBLE: - fprintf(fp, "double %g", *(jsdouble *)thing); - break; - case GCX_PRIVATE: - fprintf(fp, "private %8p", (void *)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); - } - if (atom->flags & ATOM_HIDDEN) - js_MarkAtom(cx, atom->entry.value, arg); -} - -/* - * These macros help avoid passing the GC_MARK_DEBUG-only |arg| parameter - * during recursive calls when GC_MARK_DEBUG is not defined. - */ -#ifdef GC_MARK_DEBUG -# define UNMARKED_GC_THING_FLAGS(thing, arg) \ - UnmarkedGCThingFlags(thing, arg) -# define NEXT_UNMARKED_GC_THING(vp, end, thingp, flagpp, arg) \ - NextUnmarkedGCThing(vp, end, thingp, flagpp, arg) -# define MARK_GC_THING(cx, thing, flagp, arg) \ - MarkGCThing(cx, thing, flagp, arg) -# define CALL_GC_THING_MARKER(marker, cx, thing, arg) \ - marker(cx, thing, arg) -#else -# define UNMARKED_GC_THING_FLAGS(thing, arg) \ - UnmarkedGCThingFlags(thing) -# define NEXT_UNMARKED_GC_THING(vp, end, thingp, flagpp, arg) \ - NextUnmarkedGCThing(vp, end, thingp, flagpp) -# define MARK_GC_THING(cx, thing, flagp, arg) \ - MarkGCThing(cx, thing, flagp) -# define CALL_GC_THING_MARKER(marker, cx, thing, arg) \ - marker(cx, thing, NULL) -#endif - -static uint8 * -UNMARKED_GC_THING_FLAGS(void *thing, void *arg) -{ - uint8 flags, *flagp; - - if (!thing) - return NULL; - - 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 NULL; - - return flagp; -} - -static jsval * -NEXT_UNMARKED_GC_THING(jsval *vp, jsval *end, void **thingp, uint8 **flagpp, - void *arg) -{ - jsval v; - void *thing; - uint8 *flagp; - - while (vp < end) { - v = *vp; - if (JSVAL_IS_GCTHING(v)) { - thing = JSVAL_TO_GCTHING(v); - flagp = UNMARKED_GC_THING_FLAGS(thing, arg); - if (flagp) { - *thingp = thing; - *flagpp = flagp; - return vp; - } - } - vp++; - } - return NULL; -} - -static void -DeutschSchorrWaite(JSContext *cx, void *thing, uint8 *flagp); - -static JSBool -MARK_GC_THING(JSContext *cx, void *thing, uint8 *flagp, void *arg) -{ - JSRuntime *rt; - JSObject *obj; - jsval v, *vp, *end; - JSString *str; - void *next_thing; - uint8 *next_flagp; -#ifdef JS_GCMETER - uint32 tailCallNesting; -#endif -#ifdef GC_MARK_DEBUG - JSScope *scope; - JSScopeProperty *sprop; - char name[32]; -#endif - int stackDummy; - - rt = cx->runtime; - METER(tailCallNesting = 0); - METER(if (++rt->gcStats.cdepth > rt->gcStats.maxcdepth) - rt->gcStats.maxcdepth = rt->gcStats.cdepth); - -#ifndef GC_MARK_DEBUG - start: -#endif - JS_ASSERT(flagp); - METER(if (++rt->gcStats.depth > rt->gcStats.maxdepth) - rt->gcStats.maxdepth = rt->gcStats.depth); - if (*flagp & GCF_MARK) { - /* - * This should happen only if recursive MARK_GC_THING marks flags - * already stored in the caller's *next_flagp. - */ - goto out; - } - - *flagp |= GCF_MARK; - -#ifdef GC_MARK_DEBUG - if (js_DumpGCHeap) - gc_dump_thing(thing, *flagp, arg, js_DumpGCHeap); -#endif - - switch (*flagp & GCF_TYPEMASK) { - case GCX_OBJECT: - /* If obj->slots is null, obj must be a newborn. */ - obj = (JSObject *) thing; - vp = obj->slots; - if (!vp) - goto out; - - /* Switch to Deutsch-Schorr-Waite if we exhaust our stack quota. */ - if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - METER(rt->gcStats.dswmark++); - DeutschSchorrWaite(cx, thing, flagp); - goto out; - } - - /* Mark slots if they are small enough to be GC-allocated. */ - if ((vp[-1] + 1) * sizeof(jsval) <= GC_NBYTES_MAX) - GC_MARK(cx, vp - 1, "slots", arg); - - /* Set up local variables to loop over unmarked things. */ - end = vp + ((obj->map->ops->mark) - ? CALL_GC_THING_MARKER(obj->map->ops->mark, cx, obj, arg) - : JS_MIN(obj->map->freeslot, obj->map->nslots)); - - vp = NEXT_UNMARKED_GC_THING(vp, end, &thing, &flagp, arg); - if (!vp) - goto out; - v = *vp; - - /* - * Here, thing is the first value in obj->slots referring to an - * unmarked GC-thing. - */ -#ifdef GC_MARK_DEBUG - scope = OBJ_IS_NATIVE(obj) ? OBJ_SCOPE(obj) : NULL; -#endif - for (;;) { - /* Check loop invariants. */ - JS_ASSERT(v == *vp && JSVAL_IS_GCTHING(v)); - JS_ASSERT(thing == JSVAL_TO_GCTHING(v)); - JS_ASSERT(flagp == js_GetGCThingFlags(thing)); - -#ifdef GC_MARK_DEBUG - 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, js_proto_str); - break; - case JSSLOT_PARENT: - strcpy(name, js_parent_str); - 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 - - do { - vp = NEXT_UNMARKED_GC_THING(vp+1, end, &next_thing, &next_flagp, - arg); - if (!vp) { - /* - * Here thing came from the last unmarked GC-thing slot. - * We can eliminate tail recursion unless GC_MARK_DEBUG - * is defined. - */ -#ifdef GC_MARK_DEBUG - GC_MARK(cx, thing, name, arg); - goto out; -#else - METER(++tailCallNesting); - goto start; -#endif - } - } while (next_thing == thing); - v = *vp; - -#ifdef GC_MARK_DEBUG - GC_MARK(cx, thing, name, arg); -#else - MARK_GC_THING(cx, thing, flagp, arg); -#endif - thing = next_thing; - flagp = next_flagp; - } - 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)) { - thing = JSSTRDEP_BASE(str); - flagp = UNMARKED_GC_THING_FLAGS(thing, arg); - if (flagp) { -#ifdef GC_MARK_DEBUG - GC_MARK(cx, thing, "base", arg); - goto out; -#else - METER(++tailCallNesting); - goto start; -#endif - } - } - break; - -#if JS_HAS_XML_SUPPORT - case GCX_NAMESPACE: - CALL_GC_THING_MARKER(js_MarkXMLNamespace, cx, (JSXMLNamespace *)thing, - arg); - break; - - case GCX_QNAME: - CALL_GC_THING_MARKER(js_MarkXMLQName, cx, (JSXMLQName *)thing, arg); - break; - - case GCX_XML: - CALL_GC_THING_MARKER(js_MarkXML, cx, (JSXML *)thing, arg); - break; -#endif - } - -out: - METER(rt->gcStats.depth -= 1 + tailCallNesting); - METER(rt->gcStats.cdepth--); - return JS_TRUE; -} - -/* - * An invalid object reference that's distinct from JSVAL_TRUE and JSVAL_FALSE - * when tagged as a boolean. Used to indicate empty DSW mark stack. - * - * Reversed pointers that link the DSW mark stack through obj->slots entries - * are also tagged as booleans so we can find each pointer and unreverse it. - * Because no object pointer is <= 16, these values can be distinguished from - * JSVAL_EMPTY, JSVAL_TRUE, and JSVAL_FALSE. - */ -#define JSVAL_EMPTY (2 << JSVAL_TAGBITS) - -/* - * To optimize native objects to avoid O(n^2) explosion in pathological cases, - * we use a dswIndex member of JSScope to tell where in obj->slots to find the - * reversed pointer. Scrounging space in JSScope by packing existing members - * tighter yielded 16 bits of index, which we use directly if obj->slots has - * 64K or fewer slots. Otherwise we make scope->dswIndex a fixed-point 16-bit - * fraction of the number of slots. - */ -static JS_INLINE uint16 -EncodeDSWIndex(jsval *vp, jsval *slots) -{ - uint32 nslots, limit, index; - jsdouble d; - - nslots = slots[-1]; - limit = JS_BIT(16); - index = PTRDIFF(vp, slots, jsval); - JS_ASSERT(index < nslots); - if (nslots > limit) { - d = ((jsdouble)index / nslots) * limit; - JS_ASSERT(0 <= d && d < limit); - return (uint16) d; - } - return (uint16) index; -} - -static JS_INLINE uint32 -DecodeDSWIndex(uint16 dswIndex, jsval *slots) -{ - uint32 nslots, limit; - jsdouble d; - - nslots = slots[-1]; - limit = JS_BIT(16); - JS_ASSERT(dswIndex < nslots); - if (nslots > limit) { - d = ((jsdouble)dswIndex * nslots) / limit; - JS_ASSERT(0 <= d && d < nslots); - return (uint32) d; - } - return dswIndex; -} - -static void -DeutschSchorrWaite(JSContext *cx, void *thing, uint8 *flagp) -{ - jsval top, parent, v, *vp, *end; - JSObject *obj; - JSScope *scope; -#ifdef JS_GCMETER - JSRuntime *rt = cx->runtime; -#endif - - top = JSVAL_EMPTY; - -down: - METER(if (++rt->gcStats.dswdepth > rt->gcStats.maxdswdepth) - rt->gcStats.maxdswdepth = rt->gcStats.dswdepth); - obj = (JSObject *) thing; - parent = OBJECT_TO_JSVAL(obj); - - /* Precompute for quick testing to set and get scope->dswIndex. */ - scope = (OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->object == obj) - ? OBJ_SCOPE(obj) - : NULL; - - /* Mark slots if they are small enough to be GC-allocated. */ - vp = obj->slots; - if ((vp[-1] + 1) * sizeof(jsval) <= GC_NBYTES_MAX) - GC_MARK(cx, vp - 1, "slots", NULL); - - end = vp + ((obj->map->ops->mark) - ? obj->map->ops->mark(cx, obj, NULL) - : JS_MIN(obj->map->freeslot, obj->map->nslots)); - - *flagp |= GCF_MARK; - - for (;;) { - while ((vp = NEXT_UNMARKED_GC_THING(vp, end, &thing, &flagp, NULL)) - != NULL) { - v = *vp; - JS_ASSERT(JSVAL_TO_GCTHING(v) == thing); - - if (JSVAL_IS_OBJECT(v)) { - *vp = JSVAL_SETTAG(top, JSVAL_BOOLEAN); - top = parent; - if (scope) - scope->dswIndex = EncodeDSWIndex(vp, obj->slots); - goto down; - } - - /* Handle string and double GC-things. */ - MARK_GC_THING(cx, thing, flagp, NULL); - } - - /* If we are back at the root (or we never left it), we're done. */ - METER(rt->gcStats.dswdepth--); - if (scope) - scope->dswIndex = 0; - if (top == JSVAL_EMPTY) - return; - - /* Time to go back up the spanning tree. */ - METER(rt->gcStats.dswup++); - obj = JSVAL_TO_OBJECT(top); - vp = obj->slots; - end = vp + vp[-1]; - - /* - * If obj is native and owns its own scope, we can minimize the cost - * of searching for the reversed pointer. - */ - scope = (OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->object == obj) - ? OBJ_SCOPE(obj) - : NULL; - if (scope) - vp += DecodeDSWIndex(scope->dswIndex, vp); - - /* - * Alas, we must search for the reversed pointer. If we used the - * scope->dswIndex hint, we'll step over a few slots for objects with - * a few times 64K slots, etc. For more typical (that is, far fewer - * than 64K slots) native objects that own their own scopes, this loop - * won't iterate at all. The order of complexity for host objects and - * unmutated native objects is O(n^2), but n (4 or 5 in most cases) is - * low enough that we don't care. - * - * We cannot use a reversed pointer into obj->slots, because there - * is no way to find an object from an address within its slots. - */ - v = *vp; - while (v <= JSVAL_TRUE || !JSVAL_IS_BOOLEAN(v)) { - METER(rt->gcStats.dswupstep++); - JS_ASSERT(vp + 1 < end); - v = *++vp; - } - - *vp++ = parent; - parent = top; - top = JSVAL_CLRTAG(v); - } -} - -void -js_MarkGCThing(JSContext *cx, void *thing, void *arg) -{ - uint8 *flagp; - - flagp = UNMARKED_GC_THING_FLAGS(thing, arg); - if (!flagp) - return; - MARK_GC_THING(cx, thing, flagp, arg); -} - -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 - uintN i; - JSArena *a; - jsuword firstpage; - JSBool root_points_to_gcArenaPool = JS_FALSE; - void *thing = JSVAL_TO_GCTHING(v); - - for (i = 0; i < GC_NUM_FREELISTS; i++) { - for (a = cx->runtime->gcArenaPool[i].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; - JSTempValueRooter *tvr; - size_t nbytes, nflags; - JSArena *a, **ap; - uint8 flags, *flagp, *split; - JSGCThing *thing, *limit, **flp, **oflp; - GCFinalizeOp finalizer; - uint32 *bytesptr; - 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 mutator 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++); - rt->gcPoke = JS_FALSE; - -#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_notme - { 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(cx); - js_MarkScriptFilenames(rt, gcflags); - js_MarkNativeIteratorStates(cx); - - 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) { - if (fp->fun->nargs > nslots) - nslots = fp->fun->nargs; - nslots += fp->fun->extra; - } - 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->xmlNamespace) - GC_MARK(cx, fp->xmlNamespace, "xmlNamespace", 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); - for (i = 0; i < GCX_NTYPES; i++) - GC_MARK(cx, acx->newborn[i], gc_typenames[i], NULL); - if (acx->lastAtom) - GC_MARK_ATOM(cx, acx->lastAtom, NULL); - if (JSVAL_IS_GCTHING(acx->lastInternalResult)) { - thing = JSVAL_TO_GCTHING(acx->lastInternalResult); - if (thing) - GC_MARK(cx, thing, "lastInternalResult", 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 (acx->localRootStack) - js_MarkLocalRoots(cx, acx->localRootStack); - for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { - if (tvr->count == -1) { - if (JSVAL_IS_GCTHING(tvr->u.value)) { - GC_MARK(cx, JSVAL_TO_GCTHING(tvr->u.value), - "tvr->u.value", NULL); - } - } else if (tvr->count == -2) { - tvr->u.marker(cx, tvr); - } else { - JS_ASSERT(tvr->count >= 0); - GC_MARK_JSVALS(cx, tvr->count, tvr->u.array, "tvr->u.array"); - } - } - - if (acx->sharpObjectMap.depth > 0) - js_GCMarkSharpMap(cx, &acx->sharpObjectMap); - } -#ifdef DUMP_CALL_TABLE - js_DumpCallTable(cx); -#endif - - 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. - * - * Finalize smaller objects before larger, to guarantee finalization of - * GC-allocated obj->slots after obj. See FreeSlots in jsobj.c. - */ - js_SweepAtomState(&rt->atomState); - js_SweepScopeProperties(rt); - for (i = 0; i < GC_NUM_FREELISTS; i++) { - nbytes = GC_FREELIST_NBYTES(i); - nflags = nbytes / sizeof(JSGCThing); - - for (a = rt->gcArenaPool[i].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 += nflags) { - if (((jsuword)thing & GC_PAGE_MASK) == 0) { - thing = (JSGCThing *) FIRST_THING((jsuword)thing, nbytes); - flagp = js_GetGCThingFlags(thing); - } - flags = *flagp; - if (flags & GCF_MARK) { - *flagp &= ~GCF_MARK; - } else if (!(flags & (GCF_LOCK | 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; - - bytesptr = (type == GCX_PRIVATE) - ? &rt->gcPrivateBytes - : &rt->gcBytes; - JS_ASSERT(*bytesptr >= nbytes + nflags); - *bytesptr -= nbytes + nflags; - } - flagp += nflags; - if (JS_UPTRDIFF(flagp, split) < nflags) - flagp += GC_THINGS_SIZE; - } - } - } - - /* - * Sweep script filenames after sweeping functions in the generic loop - * above. In this way when scripted function's finalizer destroys script - * triggering a call to rt->destroyScriptHook, the hook can still access - * script's filename. See bug 323267. - */ - js_SweepScriptFilenames(rt); - - /* - * Free phase. - * Free any unused arenas and rebuild the JSGCThing freelist. - */ - for (i = 0; i < GC_NUM_FREELISTS; i++) { - ap = &rt->gcArenaPool[i].first.next; - a = *ap; - if (!a) - continue; - - all_clear = JS_TRUE; - flp = oflp = &rt->gcFreeList[i]; - *flp = NULL; - METER(rt->gcStats.freelen[i] = 0); - - nbytes = GC_FREELIST_NBYTES(i); - nflags = nbytes / sizeof(JSGCThing); - do { - flagp = (uint8 *) a->base; - split = (uint8 *) FIRST_THING_PAGE(a); - limit = (JSGCThing *) a->avail; - for (thing = (JSGCThing *) split; thing < limit; thing += nflags) { - if (((jsuword)thing & GC_PAGE_MASK) == 0) { - thing = (JSGCThing *) FIRST_THING((jsuword)thing, nbytes); - flagp = js_GetGCThingFlags(thing); - } - if (*flagp != GCF_FINAL) { - all_clear = JS_FALSE; - } else { - thing->flagp = flagp; - *flp = thing; - flp = &thing->next; - METER(rt->gcStats.freelen[i]++); - } - flagp += nflags; - if (JS_UPTRDIFF(flagp, split) < nflags) - flagp += GC_THINGS_SIZE; - } - - if (all_clear) { - JS_ARENA_DESTROY(&rt->gcArenaPool[i], 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_notme - { extern void DumpSrcNoteSizeHist(); - DumpSrcNoteSizeHist(); - printf("GC HEAP SIZE %lu (%lu)\n", - (unsigned long)rt->gcBytes, (unsigned long)rt->gcPrivateBytes); - } -#endif - - JS_LOCK_GC(rt); - if (rt->gcLevel > 1 || rt->gcPoke) { - rt->gcLevel = 1; - rt->gcPoke = JS_FALSE; - JS_UNLOCK_GC(rt); - goto restart; - } - js_EnablePropertyCache(cx); - rt->gcLevel = 0; - rt->gcLastBytes = rt->gcBytes; - 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 deleted file mode 100644 index efc13194e..000000000 --- a/src/dom/js/jsgc.h +++ /dev/null @@ -1,272 +0,0 @@ -/* -*- 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_PRIVATE 4 /* private (unscanned) data */ -#define GCX_NAMESPACE 5 /* JSXMLNamespace */ -#define GCX_QNAME 6 /* JSXMLQName */ -#define GCX_XML 7 /* JSXML */ -#define GCX_EXTERNAL_STRING 8 /* JSString w/ external chars */ - -#define GCX_NTYPES_LOG2 4 /* 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_SYSTEM JS_BIT(GCX_NTYPES_LOG2 + 2) -#define GCF_LOCKSHIFT (GCX_NTYPES_LOG2 + 3) /* lock bit shift */ -#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); - -/* - * The private JSGCThing struct, which describes a gcFreeList element. - */ -struct JSGCThing { - JSGCThing *next; - uint8 *flagp; -}; - -#define GC_NBYTES_MAX (10 * sizeof(JSGCThing)) -#define GC_NUM_FREELISTS (GC_NBYTES_MAX / sizeof(JSGCThing)) -#define GC_FREELIST_NBYTES(i) (((i) + 1) * sizeof(JSGCThing)) -#define GC_FREELIST_INDEX(n) (((n) / sizeof(JSGCThing)) - 1) - -extern void * -js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes); - -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 - -extern JS_FRIEND_DATA(FILE *) js_DumpGCHeap; -JS_EXTERN_DATA(void *) js_LiveThingToFind; - -#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_NewGCThing, due to a - * malloc failure or the 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 DEBUG_notme -#define JS_GCMETER 1 -#endif - -#ifdef JS_GCMETER - -typedef struct JSGCStats { - uint32 alloc; /* number of allocation attempts */ - uint32 freelen[GC_NUM_FREELISTS]; - /* gcFreeList lengths */ - uint32 recycle[GC_NUM_FREELISTS]; - /* number of things recycled through gcFreeList */ - uint32 retry; /* allocation attempt retries after running the GC */ - uint32 retryhalt; /* allocation retries halted by the branch callback */ - uint32 fail; /* allocation failures */ - uint32 finalfail; /* finalizer calls allocator failures */ - uint32 lockborn; /* things born locked */ - uint32 lock; /* valid lock calls */ - uint32 unlock; /* valid unlock calls */ - uint32 depth; /* mark tail recursion depth */ - uint32 maxdepth; /* maximum mark tail recursion depth */ - uint32 cdepth; /* mark recursion depth of C functions */ - uint32 maxcdepth; /* maximum mark recursion depth of C functions */ - uint32 dswmark; /* mark C stack overflows => Deutsch-Schorr-Waite */ - uint32 dswdepth; /* DSW mark depth */ - uint32 maxdswdepth;/* maximum DSW mark depth */ - uint32 dswup; /* DSW moves up the mark spanning tree */ - uint32 dswupstep; /* steps in obj->slots to find DSW-reversed pointer */ - 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 JS_FRIEND_API(void) -js_DumpGCStats(JSRuntime *rt, FILE *fp); - -#endif /* JS_GCMETER */ - -#ifdef DEBUG_notme -#define TOO_MUCH_GC 1 -#endif - -#ifdef WAY_TOO_MUCH_GC -#define TOO_MUCH_GC 1 -#endif - -JS_END_EXTERN_C - -#endif /* jsgc_h___ */ diff --git a/src/dom/js/jshash.c b/src/dom/js/jshash.c deleted file mode 100644 index 0f22b5e39..000000000 --- a/src/dom/js/jshash.c +++ /dev/null @@ -1,471 +0,0 @@ -/* -*- 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 -#include -#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); - 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; - 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 -#include - -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 deleted file mode 100644 index 85e3cf811..000000000 --- a/src/dom/js/jshash.h +++ /dev/null @@ -1,152 +0,0 @@ -/* -*- 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 -#include -#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 deleted file mode 100644 index 096610cf3..000000000 --- a/src/dom/js/jsinterp.c +++ /dev/null @@ -1,5564 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=78: - * - * ***** 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 bytecode interpreter. - */ -#include "jsstddef.h" -#include -#include -#include -#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 - -#if JS_HAS_XML_SUPPORT -#include "jsxml.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]); -} - -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_PRIMITIVE(v)) { \ - obj = JSVAL_TO_OBJECT(v); \ - } else { \ - SAVE_SP(fp); \ - obj = js_ValueToNonNullObject(cx, v); \ - if (!obj) { \ - ok = JS_FALSE; \ - goto out; \ - } \ - } \ - JS_END_MACRO - -#define FETCH_OBJECT(cx, n, v, obj) \ - JS_BEGIN_MACRO \ - v = FETCH_OPND(n); \ - VALUE_TO_OBJECT(cx, v, obj); \ - STORE_OPND(n, OBJECT_TO_JSVAL(obj)); \ - 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; - } - - /* - * Store JSVAL_NULL using memset, to let compilers optimize as they see - * fit, in case a caller allocates and pushes GC-things one by one, which - * could nest a last-ditch GC that will scan this segment. - */ - memset(sp, 0, nslots * sizeof(jsval)); - 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); -} - -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 JS_TRUE; -} - -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 JS_TRUE; -} - -JSBool -js_ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp) -{ - 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]) || - !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2]))) { - thisp = cx->globalObject; - } else { - jsid id; - jsval v; - uintN attrs; - - /* Walk up the parent chain. */ - thisp = JSVAL_TO_OBJECT(fp->argv[-2]); - id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom); - for (;;) { - if (!OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs)) - return JS_FALSE; - if (JSVAL_IS_VOID(v)) - v = OBJ_GET_SLOT(cx, thisp, JSSLOT_PARENT); - if (JSVAL_IS_NULL(v)) - break; - thisp = JSVAL_TO_OBJECT(v); - } - } - } - fp->thisp = thisp; - fp->argv[-1] = OBJECT_TO_JSVAL(thisp); - return JS_TRUE; -} - -#ifdef DUMP_CALL_TABLE - -#include "jsclist.h" -#include "jshash.h" -#include "jsdtoa.h" - -typedef struct CallKey { - jsval callee; /* callee value */ - const char *filename; /* function filename or null */ - uintN lineno; /* function lineno or 0 */ -} CallKey; - -/* Compensate for typeof null == "object" brain damage. */ -#define JSTYPE_NULL JSTYPE_LIMIT -#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v)) -#define TYPENAME(t) (((t) == JSTYPE_NULL) ? js_null_str : js_type_str[t]) -#define NTYPEHIST (JSTYPE_LIMIT + 1) - -typedef struct CallValue { - uint32 total; /* total call count */ - uint32 recycled; /* LRU-recycled calls lost */ - uint16 minargc; /* minimum argument count */ - uint16 maxargc; /* maximum argument count */ - struct ArgInfo { - uint32 typeHist[NTYPEHIST]; /* histogram by type */ - JSCList lruList; /* top 10 values LRU list */ - struct ArgValCount { - JSCList lruLink; /* LRU list linkage */ - jsval value; /* recently passed value */ - uint32 count; /* number of times passed */ - char strbuf[112]; /* string conversion buffer */ - } topValCounts[10]; /* top 10 value storage */ - } argInfo[8]; -} CallValue; - -typedef struct CallEntry { - JSHashEntry entry; - CallKey key; - CallValue value; - char name[32]; /* function name copy */ -} CallEntry; - -static void * -AllocCallTable(void *pool, size_t size) -{ - return malloc(size); -} - -static void -FreeCallTable(void *pool, void *item) -{ - free(item); -} - -static JSHashEntry * -AllocCallEntry(void *pool, const void *key) -{ - return (JSHashEntry*) calloc(1, sizeof(CallEntry)); -} - -static void -FreeCallEntry(void *pool, JSHashEntry *he, uintN flag) -{ - JS_ASSERT(flag == HT_FREE_ENTRY); - free(he); -} - -static JSHashAllocOps callTableAllocOps = { - AllocCallTable, FreeCallTable, - AllocCallEntry, FreeCallEntry -}; - -JS_STATIC_DLL_CALLBACK(JSHashNumber) -js_hash_call_key(const void *key) -{ - CallKey *ck = (CallKey *) key; - JSHashNumber hash = (jsuword)ck->callee >> 3; - - if (ck->filename) { - hash = (hash << 4) ^ JS_HashString(ck->filename); - hash = (hash << 4) ^ ck->lineno; - } - return hash; -} - -JS_STATIC_DLL_CALLBACK(intN) -js_compare_call_keys(const void *k1, const void *k2) -{ - CallKey *ck1 = (CallKey *)k1, *ck2 = (CallKey *)k2; - - return ck1->callee == ck2->callee && - ((ck1->filename && ck2->filename) - ? strcmp(ck1->filename, ck2->filename) == 0 - : ck1->filename == ck2->filename) && - ck1->lineno == ck2->lineno; -} - -JSHashTable *js_CallTable; -size_t js_LogCallToSourceLimit; - -JS_STATIC_DLL_CALLBACK(intN) -CallTableDumper(JSHashEntry *he, intN k, void *arg) -{ - CallEntry *ce = (CallEntry *)he; - FILE *fp = (FILE *)arg; - uintN argc, i, n; - struct ArgInfo *ai; - JSType save, type; - JSCList *cl; - struct ArgValCount *avc; - jsval argval; - - if (ce->key.filename) { - /* We're called at the end of the mark phase, so mark our filenames. */ - js_MarkScriptFilename(ce->key.filename); - fprintf(fp, "%s:%u ", ce->key.filename, ce->key.lineno); - } else { - fprintf(fp, "@%p ", (void *) ce->key.callee); - } - - if (ce->name[0]) - fprintf(fp, "name %s ", ce->name); - fprintf(fp, "calls %lu (%lu) argc %u/%u\n", - (unsigned long) ce->value.total, - (unsigned long) ce->value.recycled, - ce->value.minargc, ce->value.maxargc); - - argc = JS_MIN(ce->value.maxargc, 8); - for (i = 0; i < argc; i++) { - ai = &ce->value.argInfo[i]; - - n = 0; - save = -1; - for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) { - if (ai->typeHist[type]) { - save = type; - ++n; - } - } - if (n == 1) { - fprintf(fp, " arg %u type %s: %lu\n", - i, TYPENAME(save), (unsigned long) ai->typeHist[save]); - } else { - fprintf(fp, " arg %u type histogram:\n", i); - for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) { - fprintf(fp, " %9s: %8lu ", - TYPENAME(type), (unsigned long) ai->typeHist[type]); - for (n = (uintN) JS_HOWMANY(ai->typeHist[type], 10); n > 0; --n) - fputc('*', fp); - fputc('\n', fp); - } - } - - fprintf(fp, " arg %u top 10 values:\n", i); - n = 1; - for (cl = ai->lruList.prev; cl != &ai->lruList; cl = cl->prev) { - avc = (struct ArgValCount *)cl; - if (!avc->count) - break; - argval = avc->value; - fprintf(fp, " %9u: %8lu %.*s (%#lx)\n", - n, (unsigned long) avc->count, - sizeof avc->strbuf, avc->strbuf, argval); - ++n; - } - } - - return HT_ENUMERATE_NEXT; -} - -void -js_DumpCallTable(JSContext *cx) -{ - char name[24]; - FILE *fp; - static uintN dumpCount; - - if (!js_CallTable) - return; - - JS_snprintf(name, sizeof name, "/tmp/calltable.dump.%u", dumpCount & 7); - dumpCount++; - fp = fopen(name, "w"); - if (!fp) - return; - - JS_HashTableEnumerateEntries(js_CallTable, CallTableDumper, fp); - fclose(fp); -} - -static void -LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv) -{ - CallKey key; - const char *name, *cstr; - JSFunction *fun; - JSHashNumber keyHash; - JSHashEntry **hep, *he; - CallEntry *ce; - uintN i, j; - jsval argval; - JSType type; - struct ArgInfo *ai; - struct ArgValCount *avc; - JSString *str; - - if (!js_CallTable) { - js_CallTable = JS_NewHashTable(1024, js_hash_call_key, - js_compare_call_keys, NULL, - &callTableAllocOps, NULL); - if (!js_CallTable) - return; - } - - key.callee = callee; - key.filename = NULL; - key.lineno = 0; - name = ""; - if (JSVAL_IS_FUNCTION(cx, callee)) { - fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(callee)); - if (fun->atom) - name = js_AtomToPrintableString(cx, fun->atom); - if (fun->interpreted) { - key.filename = fun->u.script->filename; - key.lineno = fun->u.script->lineno; - } - } - keyHash = js_hash_call_key(&key); - - hep = JS_HashTableRawLookup(js_CallTable, keyHash, &key); - he = *hep; - if (he) { - ce = (CallEntry *) he; - JS_ASSERT(strncmp(ce->name, name, sizeof ce->name) == 0); - } else { - he = JS_HashTableRawAdd(js_CallTable, hep, keyHash, &key, NULL); - if (!he) - return; - ce = (CallEntry *) he; - ce->entry.key = &ce->key; - ce->entry.value = &ce->value; - ce->key = key; - for (i = 0; i < 8; i++) { - ai = &ce->value.argInfo[i]; - JS_INIT_CLIST(&ai->lruList); - for (j = 0; j < 10; j++) - JS_APPEND_LINK(&ai->topValCounts[j].lruLink, &ai->lruList); - } - strncpy(ce->name, name, sizeof ce->name); - } - - ++ce->value.total; - if (ce->value.minargc < argc) - ce->value.minargc = argc; - if (ce->value.maxargc < argc) - ce->value.maxargc = argc; - if (argc > 8) - argc = 8; - for (i = 0; i < argc; i++) { - ai = &ce->value.argInfo[i]; - argval = argv[i]; - type = TYPEOF(cx, argval); - ++ai->typeHist[type]; - - for (j = 0; ; j++) { - if (j == 10) { - avc = (struct ArgValCount *) ai->lruList.next; - ce->value.recycled += avc->count; - avc->value = argval; - avc->count = 1; - break; - } - avc = &ai->topValCounts[j]; - if (avc->value == argval) { - ++avc->count; - break; - } - } - - /* Move avc to the back of the LRU list. */ - JS_REMOVE_LINK(&avc->lruLink); - JS_APPEND_LINK(&avc->lruLink, &ai->lruList); - - str = NULL; - cstr = ""; - switch (TYPEOF(cx, argval)) { - case JSTYPE_VOID: - cstr = js_type_str[JSTYPE_VOID]; - break; - case JSTYPE_NULL: - cstr = js_null_str; - break; - case JSTYPE_BOOLEAN: - cstr = js_boolean_str[JSVAL_TO_BOOLEAN(argval)]; - break; - case JSTYPE_NUMBER: - if (JSVAL_IS_INT(argval)) { - JS_snprintf(avc->strbuf, sizeof avc->strbuf, "%ld", - JSVAL_TO_INT(argval)); - } else { - JS_dtostr(avc->strbuf, sizeof avc->strbuf, DTOSTR_STANDARD, 0, - *JSVAL_TO_DOUBLE(argval)); - } - continue; - case JSTYPE_STRING: - str = js_QuoteString(cx, JSVAL_TO_STRING(argval), (jschar)'"'); - break; - case JSTYPE_FUNCTION: - if (JSVAL_IS_FUNCTION(cx, argval)) { - fun = (JSFunction *)JS_GetPrivate(cx, JSVAL_TO_OBJECT(argval)); - if (fun && fun->atom) { - str = ATOM_TO_STRING(fun->atom); - break; - } - } - /* FALL THROUGH */ - case JSTYPE_OBJECT: - js_LogCallToSourceLimit = sizeof avc->strbuf; - cx->options |= JSOPTION_LOGCALL_TOSOURCE; - str = js_ValueToSource(cx, argval); - cx->options &= ~JSOPTION_LOGCALL_TOSOURCE; - break; - } - if (str) - cstr = JS_GetStringBytes(str); - strncpy(avc->strbuf, cstr, sizeof avc->strbuf); - } -} - -#endif /* DUMP_CALL_TABLE */ - -/* - * 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 nslots, nvars, 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 - jsid id; - 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 = js_ComputeThis(cx, thisp, &frame); - if (!ok) - goto out2; - thisp = frame.thisp; - - id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - if (OBJECT_IS_XML(cx, thisp)) { - JSXMLObjectOps *ops; - - ops = (JSXMLObjectOps *) thisp->map->ops; - thisp = ops->getMethod(cx, thisp, id, &v); - if (!thisp) { - ok = JS_FALSE; - goto out2; - } - vp[1] = OBJECT_TO_JSVAL(thisp); - } else { - ok = OBJ_GET_PROPERTY(cx, thisp, id, &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: -#if JS_HAS_XML_SUPPORT - case JSOP_GETMETHOD: -#endif - 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(&cx->stackPool, - (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 this makes no sense -- why convert to function if clasp->call? - * XXX better to call that hook without converting - * XXX the only thing that needs fixing is liveconnect - * - * 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 (JS_VERSION_IS_1_2(cx) || - ((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; - nslots = 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); - if (fun->interpreted) { - native = NULL; - script = fun->u.script; - } else { - native = fun->u.native; - script = NULL; - } - nslots = (fun->nargs > argc) ? fun->nargs - argc : 0; - nslots += 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.xmlNamespace = NULL; - - /* Compute the 'this' parameter and store it in frame as frame.thisp. */ - ok = js_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 argument slots required by the function. */ - 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. */ - JS_ASSERT((jsval *)mark >= sp); - surplus = (jsval *)mark - sp; - nalloc -= surplus; - } - - /* Check whether we have enough space in the caller's frame. */ - if ((intN)nalloc > 0) { - /* Need space for actuals plus missing formals minus surplus. */ - newsp = js_AllocRawStack(cx, 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 == 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. */ - do { - PUSH(JSVAL_VOID); - } while (--nslots != 0); - } - JS_ASSERT(nslots == 0); - - /* Now allocate stack space for local variables. */ - if (nvars) { - JS_ASSERT((jsval *)cx->stackPool.current->avail >= frame.vars); - surplus = (jsval *)cx->stackPool.current->avail - frame.vars; - if (surplus < nvars) { - newsp = js_AllocRawStack(cx, nvars, 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. */ - do { - PUSH(JSVAL_VOID); - } while (--nvars != 0); - } - JS_ASSERT(nvars == 0); - - /* 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) { -#ifdef DUMP_CALL_TABLE - LogCall(cx, *vp, argc, frame.argv); -#endif - /* 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, script->code, &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]); - SAVE_SP(fp); - ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL); - if (ok) { - RESTORE_SP(fp); - - /* - * Store *rval in the a scoped local root if a scope is open, else in - * the cx->lastInternalResult pigeon-hole GC root, solely so users of - * js_InternalInvoke and its direct and indirect (js_ValueToString for - * example) callers do not need to manage roots for local, temporary - * references to such results. - */ - *rval = POP_OPND(); - if (JSVAL_IS_GCTHING(*rval)) { - if (cx->localRootStack) { - if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0) - ok = JS_FALSE; - } else { - cx->lastInternalResult = *rval; - } - } - } - - 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)))->interpreted && - !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 flags, jsval *result) -{ - JSInterpreterHook hook; - void *hookData, *mark; - JSStackFrame *oldfp, frame; - JSObject *obj, *tmp; - JSBool ok; - - hook = cx->runtime->executeHook; - hookData = mark = 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 = 0; - frame.argv = NULL; - frame.nvars = script->numGlobalVars; - if (frame.nvars) { - frame.vars = js_AllocRawStack(cx, frame.nvars, &mark); - if (!frame.vars) - return JS_FALSE; - memset(frame.vars, 0, frame.nvars * sizeof(jsval)); - } else { - 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 = flags; - frame.dormantNext = NULL; - frame.xmlNamespace = 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); - - /* - * Use frame.rval, not result, so the last result stays rooted across any - * GC activations nested within this js_Interpret. - */ - ok = js_Interpret(cx, script->code, &frame.rval); - *result = frame.rval; - - if (hookData) { - hook = cx->runtime->executeHook; - if (hook) - hook(cx, &frame, JS_FALSE, &ok, hookData); - } - if (mark) - js_FreeRawStack(cx, mark); - 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 | - JSPROP_GETTER | - JSPROP_SETTER), - 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, - JSObject **objp, JSProperty **propp) -{ - JSObject *obj2; - JSProperty *prop; - uintN oldAttrs, report; - JSBool isFunction; - jsval value; - const char *type, *name; - - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) - return JS_FALSE; - if (propp) { - *objp = obj2; - *propp = prop; - } - if (!prop) - return JS_TRUE; - - /* From here, return true, or goto bad on failure to drop prop. */ - if (!OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs)) - goto bad; - - /* 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)) - goto bad; - 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, JSID_TO_ATOM(id)); - if (!name) - goto bad; - return JS_ReportErrorFlagsAndNumber(cx, report, - js_GetErrorMessage, NULL, - JSMSG_REDECLARED_VAR, - type, name); - -bad: - if (propp) { - *objp = NULL; - *propp = NULL; - } - OBJ_DROP_PROPERTY(cx, obj2, prop); - return JS_FALSE; -} - -JSBool -js_StrictlyEqual(jsval lval, jsval rval) -{ - jsval ltag = JSVAL_TAG(lval), rtag = JSVAL_TAG(rval); - jsdouble ld, rd; - - if (ltag == rtag) { - if (ltag == JSVAL_STRING) { - JSString *lstr = JSVAL_TO_STRING(lval), - *rstr = JSVAL_TO_STRING(rval); - return js_CompareStrings(lstr, rstr) == 0; - } - if (ltag == JSVAL_DOUBLE) { - ld = *JSVAL_TO_DOUBLE(lval); - rd = *JSVAL_TO_DOUBLE(rval); - return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); - } - return lval == rval; - } - if (ltag == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) { - ld = *JSVAL_TO_DOUBLE(lval); - rd = JSVAL_TO_INT(rval); - return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); - } - if (JSVAL_IS_INT(lval) && rtag == JSVAL_DOUBLE) { - ld = JSVAL_TO_INT(lval); - rd = *JSVAL_TO_DOUBLE(rval); - return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); - } - return lval == rval; -} - -static JSBool -InternStringElementId(JSContext *cx, jsval idval, jsid *idp) -{ - JSAtom *atom; - - atom = js_ValueToStringAtom(cx, idval); - if (!atom) - return JS_FALSE; - *idp = ATOM_TO_JSID(atom); - return JS_TRUE; -} - -static JSBool -InternNonIntElementId(JSContext *cx, jsval idval, jsid *idp) -{ - JS_ASSERT(!JSVAL_IS_INT(idval)); - -#if JS_HAS_XML_SUPPORT - if (JSVAL_IS_OBJECT(idval)) { - *idp = OBJECT_JSVAL_TO_JSID(idval); - return JS_TRUE; - } -#endif - - return InternStringElementId(cx, idval, idp); -} - -#if JS_HAS_XML_SUPPORT -#define CHECK_ELEMENT_ID(obj, id) \ - JS_BEGIN_MACRO \ - if (JSID_IS_OBJECT(id) && !OBJECT_IS_XML(cx, obj)) { \ - SAVE_SP(fp); \ - ok = InternStringElementId(cx, OBJECT_JSID_TO_JSVAL(id), &id); \ - if (!ok) \ - goto out; \ - } \ - JS_END_MACRO - -#else -#define CHECK_ELEMENT_ID(obj, id) JS_ASSERT(!JSID_IS_OBJECT(id)) -#endif - -#ifndef MAX_INTERP_LEVEL -#if defined(XP_OS2) -#define MAX_INTERP_LEVEL 250 -#else -#define MAX_INTERP_LEVEL 1000 -#endif -#endif - -#define MAX_INLINE_CALL_COUNT 1000 - -JSBool -js_Interpret(JSContext *cx, jsbytecode *pc, 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 *endpc, *pc2; - JSOp op, op2; - const JSCodeSpec *cs; - jsatomid atomIndex; - 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 -#if JS_HAS_XML_SUPPORT - JSBool foreach = JS_FALSE; -#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. We reload onbranch after calling out to native - * functions (but not to getters, setters, or other native hooks). - */ -#define LOAD_BRANCH_CALLBACK(cx) (onbranch = (cx)->branchCallback) - - LOAD_BRANCH_CALLBACK(cx); - 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); - - /* 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 out2; - } - - /* - * Allocate operand and pc stack slots for the script's worst-case depth, - * unless we're called to interpret a part of an already active script, a - * filtering predicate expression for example. - */ - depth = (jsint) script->depth; - if (JS_LIKELY(!fp->spbase)) { - newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark); - if (!newsp) { - ok = JS_FALSE; - goto out2; - } - sp = newsp + depth; - fp->spbase = sp; - SAVE_SP(fp); - } else { - sp = fp->sp; - JS_ASSERT(JS_UPTRDIFF(sp, fp->spbase) <= depth * sizeof(jsval)); - newsp = fp->spbase - depth; - mark = NULL; - } - - endpc = script->code + script->length; - 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) { - 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: - 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: - FETCH_OBJECT(cx, -1, rval, obj); - SAVE_SP(fp); - withobj = js_NewWithObject(cx, obj, fp->scopeChain, - sp - fp->spbase - 1); - if (!withobj) - goto out; - rval = INT_TO_JSVAL(sp - fp->spbase); - 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); - JS_SetPrivate(cx, withobj, NULL); - 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_CALL_OBJECT - /* - * If frame has a call object, sync values and clear the back- - * pointer. This can happen for a lightweight function if it - * calls eval unexpectedly (in a way that is hidden from the - * compiler). See bug 325540. - */ - if (fp->callobj) - ok &= js_PutCallObject(cx, fp); -#endif -#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: - rval = FETCH_OPND(-1); - if (!JSVAL_IS_PRIMITIVE(rval)) { - obj = JSVAL_TO_OBJECT(rval); - } else { - SAVE_SP(fp); - ok = js_ValueToObject(cx, rval, &obj); - if (!ok) - goto out; - } - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - break; - -/* - * If the index value at sp[n] is not an int that fits in a jsval, it could - * be an object (an XML QName, AttributeName, or AnyName), but only if we are - * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a - * string atom id. - */ -#define FETCH_ELEMENT_ID(n, id) \ - JS_BEGIN_MACRO \ - jsval idval_ = FETCH_OPND(n); \ - if (JSVAL_IS_INT(idval_)) { \ - id = INT_JSVAL_TO_JSID(idval_); \ - } else { \ - SAVE_SP(fp); \ - ok = InternNonIntElementId(cx, idval_, &id); \ - if (!ok) \ - goto out; \ - } \ - JS_END_MACRO - -#if JS_HAS_IN_OPERATOR - case JSOP_IN: - SAVE_SP(fp); - 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; - } - obj = JSVAL_TO_OBJECT(rval); - FETCH_ELEMENT_ID(-2, id); - CHECK_ELEMENT_ID(obj, id); - ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop); - if (!ok) - goto out; - sp--; - 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 = ATOM_TO_JSID(atom); - i = -2; - goto do_forinloop; - - case JSOP_FORNAME: - atom = GET_ATOM(cx, script, pc); - id = ATOM_TO_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; - - /* - * Save sp in fp now, before any OBJ_* call-outs that might nest - * an interpreter or GC activation on this context. - */ - SAVE_SP(fp); - - /* Is this the first iteration ? */ - if (JSVAL_IS_VOID(rval)) { - /* - * Yes, create a new JSObject to hold the iterator state. - * Use NULL as the nominal parent in js_NewObject to ensure - * that we use the correct scope chain lookup to try to find the - * PropertyIterator constructor. - */ - propobj = js_NewObject(cx, &prop_iterator_class, NULL, NULL); - if (!propobj) { - ok = JS_FALSE; - goto out; - } - - /* - * Now that we've resolved the object, use the PARENT slot to - * store the object that we're iterating over. - */ - propobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj); - 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 = -#if JS_HAS_XML_SUPPORT - (foreach && OBJECT_IS_XML(cx, obj)) - ? ((JSXMLObjectOps *) obj->map->ops)->enumerateValues - (cx, obj, JSENUMERATE_INIT, &iter_state, - NULL, NULL) - : -#endif - OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, - NULL); - if (!ok) - goto out; - - /* - * Stash private iteration state into property iterator object. - * 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; - } else { - /* This is not the first iteration. Recover iterator state. */ - propobj = JSVAL_TO_OBJECT(rval); - JS_ASSERT(OBJ_GET_CLASS(cx, propobj) == &prop_iterator_class); - obj = JSVAL_TO_OBJECT(propobj->slots[JSSLOT_PARENT]); - iter_state = propobj->slots[JSSLOT_ITER_STATE]; - } - - enum_next_property: - { - jsid fid; - - /* Get the next jsid to be enumerated and store it in fid. */ - ok = -#if JS_HAS_XML_SUPPORT - (foreach && OBJECT_IS_XML(cx, obj)) - ? ((JSXMLObjectOps *) obj->map->ops)->enumerateValues - (cx, obj, JSENUMERATE_NEXT, &iter_state, - &fid, &rval) - : -#endif - OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &fid); - 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; -#if JS_HAS_XML_SUPPORT - foreach = JS_FALSE; -#endif - goto end_forinloop; - } - - ok = -#if JS_HAS_XML_SUPPORT - (foreach && OBJECT_IS_XML(cx, obj)) - ? ((JSXMLObjectOps *) obj->map->ops)->enumerateValues - (cx, obj, JSENUMERATE_INIT, &iter_state, - NULL, NULL) - : -#endif - OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, - NULL); - - /* - * 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 when looking from origobj. */ - ok = OBJ_LOOKUP_PROPERTY(cx, origobj, fid, &obj2, &prop); - if (!ok) - goto out; - if (prop) - OBJ_DROP_PROPERTY(cx, obj2, prop); - - /* - * If the id was deleted, or found in a prototype or an unrelated - * object (specifically, not in an inner object for obj), skip it. - * This means that OBJ_LOOKUP_PROPERTY implementations must return - * an object either further on the prototype chain, or related by - * the JSExtendedClass.outerObject optional hook. - */ - if (!prop) - goto enum_next_property; - if (obj != obj2) { - cond = JS_FALSE; - clasp = OBJ_GET_CLASS(cx, obj2); - if (clasp->flags & JSCLASS_IS_EXTENDED) { - JSExtendedClass *xclasp; - - xclasp = (JSExtendedClass *) clasp; - cond = xclasp->outerObject && - xclasp->outerObject(cx, obj2) == obj; - } - if (!cond) - goto enum_next_property; - } - -#if JS_HAS_XML_SUPPORT - if (foreach) { - /* Clear the local foreach flag set by our prefix bytecode. */ - foreach = JS_FALSE; - - /* If obj is not XML, we must get rval given its fid. */ - if (!OBJECT_IS_XML(cx, obj)) { - ok = OBJ_GET_PROPERTY(cx, origobj, fid, &rval); - if (!ok) - goto out; - } - } else -#endif - { - /* Make rval a string for uniformity and compatibility. */ - if (JSID_IS_ATOM(fid)) { - rval = ATOM_KEY(JSID_TO_ATOM(fid)); - } -#if JS_HAS_XML_SUPPORT - else if (JSID_IS_OBJECT(fid)) { - str = js_ValueToString(cx, OBJECT_JSID_TO_JSVAL(fid)); - if (!str) { - ok = JS_FALSE; - goto out; - } - - rval = STRING_TO_JSVAL(str); - } -#endif - else if (!JS_VERSION_IS_1_2(cx)) { - str = js_NumberToString(cx, (jsdouble) JSID_TO_INT(fid)); - if (!str) { - ok = JS_FALSE; - goto out; - } - - rval = STRING_TO_JSVAL(str); - } else { - rval = INT_JSID_TO_JSVAL(fid); - } - } - - 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); - if (i + 1 < 0) - STORE_OPND(i + 1, OBJECT_TO_JSVAL(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 \ - /* Fetch the left part and resolve it to a non-null object. */ \ - FETCH_OBJECT(cx, n, 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 the right part and resolve it to an internal id. */ \ - FETCH_ELEMENT_ID(n, id); \ - \ - /* Fetch the left part and resolve it to a non-null object. */ \ - FETCH_OBJECT(cx, n - 1, lval, obj); \ - \ - /* Ensure that id has a type suitable for use with obj. */ \ - CHECK_ELEMENT_ID(obj, id); \ - \ - /* Get or set the element, set ok false if error, true if success. */ \ - SAVE_SP(fp); \ - call; \ - if (!ok) \ - goto out; \ - 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. CACHED_GET and CACHED_SET - * use cx, obj, id, and rval from their caller's lexical environment. - */ -#define CACHED_GET(call) CACHED_GET_VP(call, &rval) - -#define CACHED_GET_VP(call,vp) \ - 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; \ - *(vp) = (slot != SPROP_INVALID_SLOT) \ - ? LOCKED_OBJ_GET_SLOT(obj, slot) \ - : JSVAL_VOID; \ - JS_UNLOCK_SCOPE(cx, scope_); \ - ok = SPROP_GET(cx, sprop, obj, obj, vp); \ - JS_LOCK_SCOPE(cx, scope_); \ - if (ok && SPROP_HAS_VALID_SLOT(sprop, scope_)) \ - LOCKED_OBJ_SET_SLOT(obj, slot, *(vp)); \ - 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 - -#define BEGIN_LITOPX_CASE(OP,PCOFF) \ - case OP: \ - atomIndex = GET_ATOM_INDEX(pc + PCOFF); \ - do_##OP: \ - atom = js_GetAtom(cx, &script->atomMap, atomIndex); - -#define END_LITOPX_CASE \ - break; \ - - BEGIN_LITOPX_CASE(JSOP_SETCONST, 0) - obj = fp->varobj; - rval = FETCH_OPND(-1); - SAVE_SP(fp); - ok = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval, - NULL, NULL, - JSPROP_ENUMERATE | JSPROP_PERMANENT | - JSPROP_READONLY, - NULL); - if (!ok) - goto out; - STORE_OPND(-1, rval); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_BINDNAME, 0) - SAVE_SP(fp); - obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom)); - if (!obj) { - ok = JS_FALSE; - goto out; - } - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - END_LITOPX_CASE - - case JSOP_SETNAME: - atom = GET_ATOM(cx, script, pc); - id = ATOM_TO_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); - obj = NULL; - 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; - -#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 = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE); \ - } \ - } else { \ - VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_NUMBER, &lval); \ - sp[-2] = 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 = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE); \ - } \ - } \ - sp--; \ - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ - JS_END_MACRO - -/* - * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies - * because they begin if/else chains, so callers must not put semicolons after - * the call expressions! - */ -#if JS_HAS_XML_SUPPORT -#define XML_EQUALITY_OP(OP) \ - if ((ltmp == JSVAL_OBJECT && \ - (obj2 = JSVAL_TO_OBJECT(lval)) && \ - OBJECT_IS_XML(cx, obj2)) || \ - (rtmp == JSVAL_OBJECT && \ - (obj2 = JSVAL_TO_OBJECT(rval)) && \ - OBJECT_IS_XML(cx, obj2))) { \ - JSXMLObjectOps *ops; \ - \ - ops = (JSXMLObjectOps *) obj2->map->ops; \ - if (obj2 == JSVAL_TO_OBJECT(rval)) \ - rval = lval; \ - SAVE_SP(fp); \ - ok = ops->equality(cx, obj2, rval, &cond); \ - if (!ok) \ - goto out; \ - cond = cond OP JS_TRUE; \ - } else - -#define XML_NAME_EQUALITY_OP(OP) \ - if (ltmp == JSVAL_OBJECT && \ - (obj2 = JSVAL_TO_OBJECT(lval)) && \ - ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) { \ - JSExtendedClass *xclasp; \ - \ - xclasp = (JSExtendedClass *) clasp; \ - SAVE_SP(fp); \ - ok = xclasp->equality(cx, obj2, rval, &cond); \ - if (!ok) \ - goto out; \ - cond = cond OP JS_TRUE; \ - } else -#else -#define XML_EQUALITY_OP(OP) /* nothing */ -#define XML_NAME_EQUALITY_OP(OP) /* nothing */ -#endif - -#define EQUALITY_OP(OP, IFNAN) \ - JS_BEGIN_MACRO \ - rval = FETCH_OPND(-1); \ - lval = FETCH_OPND(-2); \ - ltmp = JSVAL_TAG(lval); \ - rtmp = JSVAL_TAG(rval); \ - XML_EQUALITY_OP(OP) \ - 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 = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \ - } else { \ - XML_NAME_EQUALITY_OP(OP) \ - /* 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, &sp[-2]); \ - lval = sp[-2]; \ - ltmp = JSVAL_TAG(lval); \ - } else if (rtmp == JSVAL_OBJECT) { \ - VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &sp[-1]); \ - rval = sp[-1]; \ - 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 = JSDOUBLE_COMPARE(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) \ - JS_BEGIN_MACRO \ - rval = FETCH_OPND(-1); \ - lval = FETCH_OPND(-2); \ - cond = js_StrictlyEqual(lval, rval) OP JS_TRUE; \ - sp--; \ - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ - JS_END_MACRO - - case JSOP_NEW_EQ: - NEW_EQUALITY_OP(==); - break; - - case JSOP_NEW_NE: - NEW_EQUALITY_OP(!=); - break; - -#if JS_HAS_SWITCH_STATEMENT - case JSOP_CASE: - NEW_EQUALITY_OP(==); - (void) POP(); - if (cond) { - len = GET_JUMP_OFFSET(pc); - CHECK_BRANCH(len); - } else { - PUSH(lval); - } - break; - - case JSOP_CASEX: - NEW_EQUALITY_OP(==); - (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); -#if JS_HAS_XML_SUPPORT - if (!JSVAL_IS_PRIMITIVE(lval) && - (obj2 = JSVAL_TO_OBJECT(lval), OBJECT_IS_XML(cx, obj2)) && - VALUE_IS_XML(cx, rval)) { - JSXMLObjectOps *ops; - - ops = (JSXMLObjectOps *) obj2->map->ops; - SAVE_SP(fp); - ok = ops->concatenate(cx, obj2, rval, &rval); - if (!ok) - goto out; - sp--; - STORE_OPND(-1, rval); - break; - } -#endif - { - VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &sp[-2]); - lval = sp[-2]; - VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &sp[-1]); - rval = sp[-1]; - if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) { - SAVE_SP(fp); - if (cond) { - str = JSVAL_TO_STRING(lval); - ok = (str2 = js_ValueToString(cx, rval)) != NULL; - } else { - str2 = JSVAL_TO_STRING(rval); - ok = (str = js_ValueToString(cx, lval)) != 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 - SAVE_SP(fp); - 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) - { - 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. - * Use the nominal |this| parameter slot, vp[1], as a local - * root to protect this prototype, in case it has no other - * strong refs. - */ - ok = OBJ_GET_PROPERTY(cx, obj2, - ATOM_TO_JSID(rt->atomState - .classPrototypeAtom), - &vp[1]); - if (!ok) - goto out; - rval = vp[1]; - 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); - ok = js_Invoke(cx, argc, JSINVOKE_CONSTRUCT); - RESTORE_SP(fp); - LOAD_BRANCH_CALLBACK(cx); - 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 || !JS_VERSION_IS_ECMA(cx)) { - *vp = OBJECT_TO_JSVAL(obj); - break; - } - /* native [[Construct]] returning primitive is error */ - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_NEW_RESULT, - js_ValueToPrintableString(cx, rval)); - 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 = ATOM_TO_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 = ATOM_TO_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 = FETCH_OPND(-1); - SAVE_SP(fp); - type = JS_TypeOfValue(cx, rval); - atom = rt->atomState.typeAtoms[type]; - STORE_OPND(-1, ATOM_KEY(atom)); - 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 = ATOM_TO_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); - i = 0; - goto do_incop; - - case JSOP_INCPROP: - case JSOP_DECPROP: - case JSOP_PROPINC: - case JSOP_PROPDEC: - atom = GET_ATOM(cx, script, pc); - id = ATOM_TO_JSID(atom); - lval = FETCH_OPND(-1); - i = -1; - goto do_incop; - - case JSOP_INCELEM: - case JSOP_DECELEM: - case JSOP_ELEMINC: - case JSOP_ELEMDEC: - FETCH_ELEMENT_ID(-1, id); - lval = FETCH_OPND(-2); - i = -2; - - do_incop: - VALUE_TO_OBJECT(cx, lval, obj); - if (i < 0) - STORE_OPND(i, OBJECT_TO_JSVAL(obj)); - CHECK_ELEMENT_ID(obj, id); - - /* 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. Our caller must set vp to point at a GC-rooted jsval - * in which we home rtmp, to protect it from GC in case the unconverted rval - * is not a number. - */ -#define NONINT_INCREMENT_OP_MIDDLE() \ - 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; \ - *vp = rtmp; \ - } \ - (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 - - if (cs->format & JOF_POST) { - /* - * We must push early to protect the postfix increment - * or decrement result, if converted to a jsdouble from - * a non-number value, from GC nesting in the setter. - */ - vp = sp; - PUSH(JSVAL_VOID); - SAVE_SP(fp); - --i; - } -#ifdef __GNUC__ - else vp = NULL; /* suppress bogus gcc warnings */ -#endif - - NONINT_INCREMENT_OP_MIDDLE(); - } - - fp->flags |= JSFRAME_ASSIGNING; - CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)); - fp->flags &= ~JSFRAME_ASSIGNING; - if (!ok) - goto out; - sp += i; - 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 = 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_MIDDLE(); - *vp = rval; - PUSH_OPND(rtmp); - break; - -#define FAST_GLOBAL_INCREMENT_OP(SLOWOP,PRE,OP,MINMAX) \ - slot = GET_VARNO(pc); \ - JS_ASSERT(slot < fp->nvars); \ - lval = fp->vars[slot]; \ - if (JSVAL_IS_NULL(lval)) { \ - op = SLOWOP; \ - goto do_op; \ - } \ - slot = JSVAL_TO_INT(lval); \ - obj = fp->varobj; \ - rval = OBJ_GET_SLOT(cx, obj, slot); \ - if (JSVAL_IS_INT(rval) && \ - rval != INT_TO_JSVAL(JSVAL_INT_##MINMAX)) { \ - PRE = rval; \ - rval OP 2; \ - OBJ_SET_SLOT(cx, obj, slot, rval); \ - PUSH_OPND(PRE); \ - break; \ - } \ - goto do_nonint_fast_global_incop; - - case JSOP_INCGVAR: - FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, rval, +=, MAX); - case JSOP_DECGVAR: - FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, rval, -=, MIN); - case JSOP_GVARINC: - FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, rtmp, +=, MAX); - case JSOP_GVARDEC: - FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, rtmp, -=, MIN); - -#undef FAST_GLOBAL_INCREMENT_OP - - do_nonint_fast_global_incop: - vp = sp++; - SAVE_SP(fp); - NONINT_INCREMENT_OP_MIDDLE(); - OBJ_SET_SLOT(cx, obj, slot, rval); - STORE_OPND(-1, rtmp); - break; - - case JSOP_GETPROP: - /* Get an immediate atom naming the property. */ - atom = GET_ATOM(cx, script, pc); - id = ATOM_TO_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 = ATOM_TO_JSID(atom); - PROPERTY_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval))); - sp--; - STORE_OPND(-1, rval); - obj = NULL; - 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); - obj = NULL; - break; - - case JSOP_ENUMELEM: - /* Funky: the value to set is under the [obj, id] pair. */ - FETCH_ELEMENT_ID(-1, id); - FETCH_OBJECT(cx, -2, lval, obj); - CHECK_ELEMENT_ID(obj, id); - 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->interpreted && - !(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->u.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 = js_ComputeThis(cx, JSVAL_TO_OBJECT(vp[1]), &newifp->frame); - if (!ok) { - js_FreeRawStack(cx, newmark); - goto bad_inline_call; - } -#ifdef DUMP_CALL_TABLE - LogCall(cx, *vp, argc, vp + 2); -#endif - - /* 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_BRANCH_CALLBACK(cx); - 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_BRANCH_CALLBACK(cx); - 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 = ATOM_TO_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_UINT24: - i = (jsint) GET_LITERAL_INDEX(pc); - rval = INT_TO_JSVAL(i); - PUSH_OPND(rval); - break; - - case JSOP_LITERAL: - atomIndex = GET_LITERAL_INDEX(pc); - atom = js_GetAtom(cx, &script->atomMap, atomIndex); - PUSH_OPND(ATOM_KEY(atom)); - obj = NULL; - break; - - case JSOP_FINDNAME: - atomIndex = GET_LITERAL_INDEX(pc); - atom = js_GetAtom(cx, &script->atomMap, atomIndex); - SAVE_SP(fp); - obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom)); - if (!obj) { - ok = JS_FALSE; - goto out; - } - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - PUSH_OPND(ATOM_KEY(atom)); - break; - - case JSOP_LITOPX: - atomIndex = GET_LITERAL_INDEX(pc); - op = pc[1 + LITERAL_INDEX_LEN]; - switch (op) { - case JSOP_ANONFUNOBJ: goto do_JSOP_ANONFUNOBJ; - case JSOP_BINDNAME: goto do_JSOP_BINDNAME; - case JSOP_CLOSURE: goto do_JSOP_CLOSURE; - case JSOP_DEFCONST: goto do_JSOP_DEFCONST; - case JSOP_DEFFUN: goto do_JSOP_DEFFUN; - case JSOP_DEFLOCALFUN: goto do_JSOP_DEFLOCALFUN; - case JSOP_DEFVAR: goto do_JSOP_DEFVAR; -#if JS_HAS_EXPORT_IMPORT - case JSOP_EXPORTNAME: goto do_JSOP_EXPORTNAME; -#endif -#if JS_HAS_XML_SUPPORT - case JSOP_GETMETHOD: goto do_JSOP_GETMETHOD; - case JSOP_SETMETHOD: goto do_JSOP_SETMETHOD; -#endif - case JSOP_INITCATCHVAR: goto do_JSOP_INITCATCHVAR; - case JSOP_NAMEDFUNOBJ: goto do_JSOP_NAMEDFUNOBJ; - case JSOP_NUMBER: goto do_JSOP_NUMBER; - case JSOP_OBJECT: goto do_JSOP_OBJECT; -#if JS_HAS_XML_SUPPORT - case JSOP_QNAMECONST: goto do_JSOP_QNAMECONST; - case JSOP_QNAMEPART: goto do_JSOP_QNAMEPART; -#endif - case JSOP_REGEXP: goto do_JSOP_REGEXP; - case JSOP_SETCONST: goto do_JSOP_SETCONST; - case JSOP_STRING: goto do_JSOP_STRING; -#if JS_HAS_XML_SUPPORT - case JSOP_XMLCDATA: goto do_JSOP_XMLCDATA; - case JSOP_XMLCOMMENT: goto do_JSOP_XMLCOMMENT; - case JSOP_XMLOBJECT: goto do_JSOP_XMLOBJECT; - case JSOP_XMLPI: goto do_JSOP_XMLPI; -#endif - default: JS_ASSERT(0); - } - /* NOTREACHED */ - break; - - case JSOP_NUMBER: - case JSOP_STRING: - case JSOP_OBJECT: - atomIndex = GET_ATOM_INDEX(pc); - - do_JSOP_NUMBER: - do_JSOP_STRING: - do_JSOP_OBJECT: - atom = js_GetAtom(cx, &script->atomMap, atomIndex); - PUSH_OPND(ATOM_KEY(atom)); - obj = NULL; - break; - - BEGIN_LITOPX_CASE(JSOP_REGEXP, 0) - { - JSRegExp *re; - JSObject *funobj; - - /* - * Push a regexp object for the atom mapped by the bytecode at pc, - * cloning the literal's regexp object if necessary, to simulate in - * the pre-compile/execute-later case what ECMA specifies for the - * compile-and-go case: that scanning each regexp literal creates - * a single corresponding RegExp object. - * - * To support pre-compilation transparently, 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. We do this by re-wrapping the JSRegExp private - * data struct with a cloned object having the right prototype and - * parent, and having its own lastIndex property value storage. - * - * Unlike JSOP_DEFFUN and other prolog bytecodes that may clone - * literal objects, 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 initialize lazily here. - * - * XXX This code is specific to regular expression objects. If we - * need a similar op for other kinds of object literals, we should - * push cloning down under JSObjectOps and reuse code here. - */ - JS_ASSERT(ATOM_IS_OBJECT(atom)); - obj = ATOM_TO_OBJECT(atom); - JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass); - - re = (JSRegExp *) JS_GetPrivate(cx, obj); - slot = re->cloneIndex; - if (fp->fun) { - /* - * We're in function code, not global or eval code (in eval - * code, JSOP_REGEXP is never emitted). The code generator - * recorded in fp->fun->nregexps the number of re->cloneIndex - * slots that it reserved in the cloned funobj. - */ - funobj = JSVAL_TO_OBJECT(fp->argv[-2]); - slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass); - if (!JS_GetReservedSlot(cx, funobj, slot, &rval)) - return JS_FALSE; - if (JSVAL_IS_VOID(rval)) - rval = JSVAL_NULL; - } else { - /* - * We're in global code. The code generator already arranged - * via script->numGlobalVars to reserve a global variable slot - * at cloneIndex. All global variable slots are initialized - * to null, not void, for faster testing in JSOP_*GVAR cases. - */ - rval = fp->vars[slot]; -#ifdef __GNUC__ - funobj = NULL; /* suppress bogus gcc warnings */ -#endif - } - - if (JSVAL_IS_NULL(rval)) { - /* Compute the current global object in obj2. */ - obj2 = fp->scopeChain; - while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL) - obj2 = parent; - - /* - * We must home sp here, because either js_CloneRegExpObject - * or JS_SetReservedSlot could nest a last-ditch GC. We home - * pc as well, in case js_CloneRegExpObject has to lookup the - * "RegExp" class in the global object, which could entail a - * JSNewResolveOp call. - */ - SAVE_SP(fp); - - /* - * 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 everywhere (see jsobj.c's FindConstructor, - * js_ConstructObject, and js_NewObject). It's fundamental to - * the design of the language when you consider multiple global - * objects and separate compilation and execution, even though - * it is not specified fully in ECMA. - */ - if (OBJ_GET_PARENT(cx, obj) != obj2) { - obj = js_CloneRegExpObject(cx, obj, obj2); - if (!obj) { - ok = JS_FALSE; - goto out; - } - } - rval = OBJECT_TO_JSVAL(obj); - - /* Store the regexp object value in its cloneIndex slot. */ - if (fp->fun) { - if (!JS_SetReservedSlot(cx, funobj, slot, rval)) - return JS_FALSE; - } else { - fp->vars[slot] = rval; - } - } - - PUSH_OPND(rval); - obj = NULL; - } - END_LITOPX_CASE - - 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: - obj = fp->thisp; - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp->flags & JSCLASS_IS_EXTENDED) { - JSExtendedClass *xclasp; - - xclasp = (JSExtendedClass *) clasp; - if (xclasp->outerObject) { - obj = xclasp->outerObject(cx, obj); - if (!obj) { - ok = JS_FALSE; - goto out; - } - } - } - - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - 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_MASK) == JSVERSION_DEFAULT || - (cx->version & JSVERSION_MASK) >= 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_MASK) == JSVERSION_DEFAULT || - (cx->version & JSVERSION_MASK) >= 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: - SAVE_SP(fp); - 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; - - BEGIN_LITOPX_CASE(JSOP_EXPORTNAME, 0) - id = ATOM_TO_JSID(atom); - obj = fp->varobj; - SAVE_SP(fp); - 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; - END_LITOPX_CASE - - 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 = ATOM_TO_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 = INT_TO_JSID(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 = ATOM_TO_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_GETGVAR: - slot = GET_VARNO(pc); - JS_ASSERT(slot < fp->nvars); - lval = fp->vars[slot]; - if (JSVAL_IS_NULL(lval)) { - op = JSOP_NAME; - goto do_op; - } - slot = JSVAL_TO_INT(lval); - obj = fp->varobj; - rval = OBJ_GET_SLOT(cx, obj, slot); - PUSH_OPND(rval); - break; - - case JSOP_SETGVAR: - slot = GET_VARNO(pc); - JS_ASSERT(slot < fp->nvars); - rval = FETCH_OPND(-1); - lval = fp->vars[slot]; - obj = fp->varobj; - if (JSVAL_IS_NULL(lval)) { - /* - * Inline-clone and specialize JSOP_SETNAME code here because - * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval] - * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME. - */ - atom = GET_ATOM(cx, script, pc); - id = ATOM_TO_JSID(atom); - SAVE_SP(fp); - CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)); - if (!ok) - goto out; - STORE_OPND(-1, rval); - } else { - slot = JSVAL_TO_INT(lval); - GC_POKE(cx, obj->slots[slot]); - OBJ_SET_SLOT(cx, obj, slot, rval); - } - obj = NULL; - break; - - case JSOP_DEFCONST: - case JSOP_DEFVAR: - atomIndex = GET_ATOM_INDEX(pc); - - do_JSOP_DEFCONST: - do_JSOP_DEFVAR: - atom = js_GetAtom(cx, &script->atomMap, atomIndex); - 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 = ATOM_TO_JSID(atom); - SAVE_SP(fp); - ok = js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop); - if (!ok) - goto out; - - /* Bind a variable only if it's not yet defined. */ - if (!prop) { - ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL, - attrs, &prop); - if (!ok) - goto out; - JS_ASSERT(prop); - obj2 = obj; - } - - /* - * Try to optimize a property we either just created, or found - * directly in the global object, that is permanent, has a slot, - * and has stub getter and setter, into a "fast global" accessed - * by the JSOP_*GVAR opcodes. - */ - if (atomIndex < script->numGlobalVars && - (attrs & JSPROP_PERMANENT) && - obj2 == obj && - OBJ_IS_NATIVE(obj)) { - sprop = (JSScopeProperty *) prop; - if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) && - SPROP_HAS_STUB_GETTER(sprop) && - SPROP_HAS_STUB_SETTER(sprop)) { - /* - * Fast globals use fp->vars to map the global name's - * atomIndex to the permanent fp->varobj slot number, - * tagged as a jsval. The atomIndex for the global's - * name literal is identical to its fp->vars index. - */ - fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot); - } - } - - OBJ_DROP_PROPERTY(cx, obj2, prop); - break; - - BEGIN_LITOPX_CASE(JSOP_DEFFUN, 0) - { - uintN flags; - - atomIndex = GET_ATOM_INDEX(pc); - atom = js_GetAtom(cx, &script->atomMap, atomIndex); - obj = ATOM_TO_OBJECT(atom); - fun = (JSFunction *) JS_GetPrivate(cx, obj); - id = ATOM_TO_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 scope chain head from - * variables object. Hence the obj2 vs. parent distinction 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. - */ - obj2 = fp->scopeChain; - if (OBJ_GET_PARENT(cx, obj) != obj2) { - obj = js_CloneFunctionObject(cx, obj, obj2); - if (!obj) { - ok = JS_FALSE; - goto out; - } - } - - /* - * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All - * paths from here must flow through the "Restore fp->scopeChain" - * code below the OBJ_DEFINE_PROPERTY call. - */ - fp->scopeChain = obj; - rval = OBJECT_TO_JSVAL(obj); - - /* - * 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; - rval = JSVAL_VOID; - } - - /* - * 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; - SAVE_SP(fp); - ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL); - if (ok) { - ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval, - (flags & JSFUN_GETTER) - ? (JSPropertyOp) obj - : NULL, - (flags & JSFUN_SETTER) - ? (JSPropertyOp) obj - : NULL, - attrs, - &prop); - } - - /* Restore fp->scopeChain now that obj is defined in fp->varobj. */ - fp->scopeChain = obj2; - if (!ok) - goto out; - -#if 0 - if (attrs == (JSPROP_ENUMERATE | JSPROP_PERMANENT) && - script->numGlobalVars) { - /* - * As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals - * use fp->vars to map the global function name's atomIndex to - * its permanent fp->varobj slot number, tagged as a jsval. - */ - sprop = (JSScopeProperty *) prop; - fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot); - } -#endif - OBJ_DROP_PROPERTY(cx, parent, prop); - } - END_LITOPX_CASE - -#if JS_HAS_LEXICAL_CLOSURE - BEGIN_LITOPX_CASE(JSOP_DEFLOCALFUN, VARNO_LEN) - /* - * 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. - */ - slot = GET_VARNO(pc); - atom = js_GetAtom(cx, &script->atomMap, atomIndex); - obj = ATOM_TO_OBJECT(atom); - fun = (JSFunction *) JS_GetPrivate(cx, obj); - - parent = fp->scopeChain; - if (OBJ_GET_PARENT(cx, obj) != parent) { - SAVE_SP(fp); - obj = js_CloneFunctionObject(cx, obj, parent); - if (!obj) { - ok = JS_FALSE; - goto out; - } - } - fp->vars[slot] = OBJECT_TO_JSVAL(obj); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_ANONFUNOBJ, 0) - /* Push the specified function object literal. */ - 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) { - SAVE_SP(fp); - obj = js_CloneFunctionObject(cx, obj, parent); - if (!obj) { - ok = JS_FALSE; - goto out; - } - } - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - obj = NULL; - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_NAMEDFUNOBJ, 0) - /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */ - 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); - obj2 = fp->scopeChain; - parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2); - 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]. - * - * Protect parent from GC after js_CloneFunctionObject calls into - * js_NewObject, which displaces the newborn object root in cx by - * allocating the clone, then runs a last-ditch GC while trying - * to allocate the clone's slots vector. Another, multi-threaded - * path: js_CloneFunctionObject => js_NewObject => OBJ_GET_CLASS - * which may suspend the current request in ClaimScope, with the - * newborn displaced as in the first scenario. - */ - fp->scopeChain = parent; - obj = js_CloneFunctionObject(cx, JSVAL_TO_OBJECT(rval), parent); - if (!obj) { - ok = JS_FALSE; - goto out; - } - - /* - * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All - * paths from here must flow through the "Restore fp->scopeChain" - * code below the OBJ_DEFINE_PROPERTY call. - */ - fp->scopeChain = obj; - rval = OBJECT_TO_JSVAL(obj); - - /* - * 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; - rval = JSVAL_VOID; - } - ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval, - (attrs & JSFUN_GETTER) - ? (JSPropertyOp) obj - : NULL, - (attrs & JSFUN_SETTER) - ? (JSPropertyOp) obj - : NULL, - attrs | - JSPROP_ENUMERATE | JSPROP_PERMANENT | - JSPROP_READONLY, - NULL); - - /* Restore fp->scopeChain now that obj is defined in parent. */ - fp->scopeChain = obj2; - 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)); - obj = NULL; - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_CLOSURE, 0) - /* - * 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. - */ - 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. - */ - SAVE_SP(fp); - obj2 = fp->scopeChain; - if (OBJ_GET_PARENT(cx, obj) != obj2) { - obj = js_CloneFunctionObject(cx, obj, obj2); - if (!obj) { - ok = JS_FALSE; - goto out; - } - } - - /* - * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All - * paths from here must flow through the "Restore fp->scopeChain" - * code below the OBJ_DEFINE_PROPERTY call. - */ - fp->scopeChain = obj; - rval = OBJECT_TO_JSVAL(obj); - - /* - * 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; - rval = JSVAL_VOID; - } - parent = fp->varobj; - ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval, - (attrs & JSFUN_GETTER) - ? (JSPropertyOp) obj - : NULL, - (attrs & JSFUN_SETTER) - ? (JSPropertyOp) obj - : NULL, - attrs | JSPROP_ENUMERATE - | JSPROP_PERMANENT, - &prop); - - /* Restore fp->scopeChain now that obj is defined in fp->varobj. */ - fp->scopeChain = obj2; - if (!ok) { - cx->newborn[GCX_OBJECT] = NULL; - goto out; - } - -#if 0 - if (attrs == 0 && script->numGlobalVars) { - /* - * As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals - * use fp->vars to map the global function name's atomIndex to - * its permanent fp->varobj slot number, tagged as a jsval. - */ - sprop = (JSScopeProperty *) prop; - fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot); - } -#endif - OBJ_DROP_PROPERTY(cx, parent, prop); - END_LITOPX_CASE -#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 = ATOM_TO_JSID(atom); - rval = FETCH_OPND(-1); - i = -1; - goto gs_pop_lval; - - case JSOP_SETELEM: - rval = FETCH_OPND(-1); - FETCH_ELEMENT_ID(-2, id); - i = -2; - gs_pop_lval: - FETCH_OBJECT(cx, i - 1, lval, obj); - break; - -#if JS_HAS_INITIALIZERS - case JSOP_INITPROP: - JS_ASSERT(sp - fp->spbase >= 2); - rval = FETCH_OPND(-1); - i = -1; - atom = GET_ATOM(cx, script, pc); - id = ATOM_TO_JSID(atom); - goto gs_get_lval; - - case JSOP_INITELEM: - JS_ASSERT(sp - fp->spbase >= 3); - rval = FETCH_OPND(-1); - FETCH_ELEMENT_ID(-2, id); - i = -2; - 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); - } - - /* Ensure that id has a type suitable for use with obj. */ - CHECK_ELEMENT_ID(obj, id); - - SAVE_SP(fp); - 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, NULL, NULL); - if (!ok) - goto out; - - ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter, - attrs, NULL); - if (!ok) - goto out; - - obj = NULL; - 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 = ATOM_TO_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); - - /* Ensure that id has a type suitable for use with obj. */ - CHECK_ELEMENT_ID(obj, id); - - /* Set the property named by obj[id] to rval. */ - SAVE_SP(fp); - ok = OBJ_SET_PROPERTY(cx, obj, id, &rval); - if (!ok) - goto out; - sp += i; - break; - -#if JS_HAS_SHARP_VARS - case JSOP_DEFSHARP: - SAVE_SP(fp); - 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 = INT_TO_JSID(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 = INT_TO_JSID(i); - obj = fp->sharpArray; - if (!obj) { - rval = JSVAL_VOID; - } else { - SAVE_SP(fp); - 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; - - obj = fp->scopeChain; - while (OBJ_GET_CLASS(cx, obj) == &js_WithClass && - JS_GetPrivate(cx, obj) == fp && - OBJ_BLOCK_DEPTH(cx, obj) >= i) { - obj = OBJ_GET_PARENT(cx, obj); - } - fp->scopeChain = obj; - break; - - case JSOP_GOSUB: - JS_ASSERT(cx->exception != JSVAL_HOLE); - if (!cx->throwing) { - lval = JSVAL_HOLE; - } else { - lval = cx->exception; - cx->throwing = JS_FALSE; - } - PUSH(lval); - i = PTRDIFF(pc, script->main, jsbytecode) + len; - len = GET_JUMP_OFFSET(pc); - PUSH(INT_TO_JSVAL(i)); - break; - - case JSOP_GOSUBX: - JS_ASSERT(cx->exception != JSVAL_HOLE); - lval = cx->throwing ? cx->exception : JSVAL_HOLE; - PUSH(lval); - 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)); - lval = POP(); - if (lval != JSVAL_HOLE) { - /* - * Exception was pending during finally, throw it *before* we - * adjust pc, because pc indexes into script->trynotes. This - * turns out not to be necessary, but it seems clearer. And - * it points out a FIXME: 350509, due to Igor Bukanov. - */ - cx->throwing = JS_TRUE; - cx->exception = lval; - ok = JS_FALSE; - goto out; - } - i = JSVAL_TO_INT(rval); - pc = script->main + i; - len = 0; - break; - - case JSOP_EXCEPTION: - PUSH(cx->exception); - cx->throwing = JS_FALSE; - break; - - case JSOP_THROWING: - JS_ASSERT(!cx->throwing); - cx->throwing = JS_TRUE; - 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; - - BEGIN_LITOPX_CASE(JSOP_INITCATCHVAR, 0) - /* Load the value into rval, while keeping it live on stack. */ - JS_ASSERT(sp - fp->spbase >= 2); - rval = FETCH_OPND(-1); - - /* Get the immediate catch variable name into id. */ - id = ATOM_TO_JSID(atom); - - /* Find the object being initialized at top of stack. */ - lval = FETCH_OPND(-2); - JS_ASSERT(JSVAL_IS_OBJECT(lval)); - obj = JSVAL_TO_OBJECT(lval); - - SAVE_SP(fp); - - /* - * It's possible for an evil script to substitute a random object - * for the new object. Check to make sure that we don't override a - * readonly property with the below OBJ_DEFINE_PROPERTY. - */ - ok = OBJ_GET_ATTRIBUTES(cx, obj, id, NULL, &attrs); - if (!ok) - goto out; - if (!(attrs & (JSPROP_READONLY | JSPROP_PERMANENT | - JSPROP_GETTER | JSPROP_SETTER))) { - /* 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; - } - - /* Now that we're done with rval, pop it. */ - sp--; - END_LITOPX_CASE -#endif /* JS_HAS_EXCEPTIONS */ - -#if JS_HAS_INSTANCEOF - case JSOP_INSTANCEOF: - rval = FETCH_OPND(-1); - if (JSVAL_IS_PRIMITIVE(rval) || - !(obj = JSVAL_TO_OBJECT(rval))->map->ops->hasInstance) { - 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; - } - lval = FETCH_OPND(-2); - cond = JS_FALSE; - 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 */ - -#if JS_HAS_XML_SUPPORT - case JSOP_DEFXMLNS: - rval = POP(); - SAVE_SP(fp); - ok = js_SetDefaultXMLNamespace(cx, rval); - if (!ok) - goto out; - break; - - case JSOP_ANYNAME: - SAVE_SP(fp); - ok = js_GetAnyName(cx, &rval); - if (!ok) - goto out; - PUSH_OPND(rval); - break; - - BEGIN_LITOPX_CASE(JSOP_QNAMEPART, 0) - PUSH_OPND(ATOM_KEY(atom)); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_QNAMECONST, 0) - rval = ATOM_KEY(atom); - lval = FETCH_OPND(-1); - SAVE_SP(fp); - obj = js_ConstructXMLQNameObject(cx, lval, rval); - if (!obj) { - ok = JS_FALSE; - goto out; - } - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - END_LITOPX_CASE - - case JSOP_QNAME: - rval = FETCH_OPND(-1); - lval = FETCH_OPND(-2); - SAVE_SP(fp); - obj = js_ConstructXMLQNameObject(cx, lval, rval); - if (!obj) { - ok = JS_FALSE; - goto out; - } - sp--; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - break; - - case JSOP_TOATTRNAME: - rval = FETCH_OPND(-1); - SAVE_SP(fp); - ok = js_ToAttributeName(cx, &rval); - if (!ok) - goto out; - STORE_OPND(-1, rval); - break; - - case JSOP_TOATTRVAL: - rval = FETCH_OPND(-1); - JS_ASSERT(JSVAL_IS_STRING(rval)); - SAVE_SP(fp); - str = js_EscapeAttributeValue(cx, JSVAL_TO_STRING(rval)); - if (!str) { - ok = JS_FALSE; - goto out; - } - STORE_OPND(-1, STRING_TO_JSVAL(str)); - break; - - case JSOP_ADDATTRNAME: - case JSOP_ADDATTRVAL: - rval = FETCH_OPND(-1); - lval = FETCH_OPND(-2); - str = JSVAL_TO_STRING(lval); - str2 = JSVAL_TO_STRING(rval); - SAVE_SP(fp); - str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2); - if (!str) { - ok = JS_FALSE; - goto out; - } - sp--; - STORE_OPND(-1, STRING_TO_JSVAL(str)); - break; - - case JSOP_BINDXMLNAME: - lval = FETCH_OPND(-1); - SAVE_SP(fp); - ok = js_FindXMLProperty(cx, lval, &obj, &rval); - if (!ok) - goto out; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - PUSH_OPND(rval); - break; - - case JSOP_SETXMLNAME: - obj = JSVAL_TO_OBJECT(FETCH_OPND(-3)); - lval = FETCH_OPND(-2); - rval = FETCH_OPND(-1); - SAVE_SP(fp); - ok = js_SetXMLProperty(cx, obj, lval, &rval); - if (!ok) - goto out; - sp -= 2; - STORE_OPND(-1, rval); - obj = NULL; - break; - - case JSOP_XMLNAME: - lval = FETCH_OPND(-1); - SAVE_SP(fp); - ok = js_FindXMLProperty(cx, lval, &obj, &rval); - if (!ok) - goto out; - ok = js_GetXMLProperty(cx, obj, rval, &rval); - if (!ok) - goto out; - STORE_OPND(-1, rval); - break; - - case JSOP_DESCENDANTS: - case JSOP_DELDESC: - FETCH_OBJECT(cx, -2, lval, obj); - rval = FETCH_OPND(-1); - SAVE_SP(fp); - ok = js_GetXMLDescendants(cx, obj, rval, &rval); - if (!ok) - goto out; - - if (op == JSOP_DELDESC) { - sp[-1] = rval; /* set local root */ - ok = js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval)); - if (!ok) - goto out; - rval = JSVAL_TRUE; /* always succeed */ - } - - sp--; - STORE_OPND(-1, rval); - break; - - case JSOP_FILTER: - FETCH_OBJECT(cx, -1, lval, obj); - len = GET_JUMP_OFFSET(pc); - SAVE_SP(fp); - ok = js_FilterXMLList(cx, obj, pc + cs->length, &rval); - if (!ok) - goto out; - JS_ASSERT(fp->sp == sp); - STORE_OPND(-1, rval); - break; - - case JSOP_ENDFILTER: - *result = POP_OPND(); - goto out; - - case JSOP_STARTXML: - case JSOP_STARTXMLEXPR: - break; - - case JSOP_TOXML: - rval = FETCH_OPND(-1); - SAVE_SP(fp); - obj = js_ValueToXMLObject(cx, rval); - if (!obj) { - ok = JS_FALSE; - goto out; - } - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - break; - - case JSOP_TOXMLLIST: - rval = FETCH_OPND(-1); - SAVE_SP(fp); - obj = js_ValueToXMLListObject(cx, rval); - if (!obj) { - ok = JS_FALSE; - goto out; - } - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - break; - - case JSOP_XMLTAGEXPR: - rval = FETCH_OPND(-1); - SAVE_SP(fp); - str = js_ValueToString(cx, rval); - if (!str) { - ok = JS_FALSE; - goto out; - } - STORE_OPND(-1, STRING_TO_JSVAL(str)); - break; - - case JSOP_XMLELTEXPR: - rval = FETCH_OPND(-1); - SAVE_SP(fp); - if (VALUE_IS_XML(cx, rval)) { - str = js_ValueToXMLString(cx, rval); - } else { - str = js_ValueToString(cx, rval); - if (str) - str = js_EscapeElementValue(cx, str); - } - if (!str) { - ok = JS_FALSE; - goto out; - } - STORE_OPND(-1, STRING_TO_JSVAL(str)); - break; - - BEGIN_LITOPX_CASE(JSOP_XMLOBJECT, 0) - SAVE_SP(fp); - obj = js_CloneXMLObject(cx, ATOM_TO_OBJECT(atom)); - if (!obj) { - ok = JS_FALSE; - goto out; - } - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - obj = NULL; - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_XMLCDATA, 0) - str = ATOM_TO_STRING(atom); - obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); - if (!obj) { - ok = JS_FALSE; - goto out; - } - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_XMLCOMMENT, 0) - str = ATOM_TO_STRING(atom); - obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); - if (!obj) { - ok = JS_FALSE; - goto out; - } - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_XMLPI, 0) - str = ATOM_TO_STRING(atom); - rval = FETCH_OPND(-1); - str2 = JSVAL_TO_STRING(rval); - SAVE_SP(fp); - obj = js_NewXMLSpecialObject(cx, - JSXML_CLASS_PROCESSING_INSTRUCTION, - str, str2); - if (!obj) { - ok = JS_FALSE; - goto out; - } - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_GETMETHOD, 0) - /* Get an immediate atom naming the property. */ - id = ATOM_TO_JSID(atom); - FETCH_OBJECT(cx, -1, lval, obj); - SAVE_SP(fp); - - /* Special-case XML object method lookup, per ECMA-357. */ - if (OBJECT_IS_XML(cx, obj)) { - JSXMLObjectOps *ops; - - ops = (JSXMLObjectOps *) obj->map->ops; - obj = ops->getMethod(cx, obj, id, &rval); - if (!obj) - ok = JS_FALSE; - } else { - CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)); - } - if (!ok) - goto out; - STORE_OPND(-1, rval); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_SETMETHOD, 0) - /* Get an immediate atom naming the property. */ - id = ATOM_TO_JSID(atom); - rval = FETCH_OPND(-1); - FETCH_OBJECT(cx, -2, lval, obj); - SAVE_SP(fp); - - /* Special-case XML object method lookup, per ECMA-357. */ - if (OBJECT_IS_XML(cx, obj)) { - JSXMLObjectOps *ops; - - ops = (JSXMLObjectOps *) obj->map->ops; - ok = ops->setMethod(cx, obj, id, &rval); - } else { - CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)); - } - if (!ok) - goto out; - --sp; - STORE_OPND(-1, rval); - obj = NULL; - END_LITOPX_CASE - - case JSOP_GETFUNNS: - ok = js_GetFunctionNamespace(cx, &rval); - if (!ok) - goto out; - PUSH_OPND(rval); - break; - - case JSOP_FOREACH: - foreach = JS_TRUE; - break; -#endif /* JS_HAS_XML_SUPPORT */ - - 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); - if (op == JSOP_FORELEM && sp[-1] == JSVAL_FALSE) - --ndefs; - 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) : ""); - } - fputc('\n', tracefp); - } -#endif - } -out: - -#if JS_HAS_EXCEPTIONS - if (!ok) { - /* - * Has an exception been raised? Also insist that we are in the - * interpreter activation that pushed fp's operand stack, to avoid - * catching exceptions within XML filtering predicate expressions, - * such as the one from tests/e4x/Regress/regress-301596.js: - * - * try { - * .(@a == 1); - * throw 5; - * } catch (e) { - * } - * - * The inner interpreter activation executing the predicate bytecode - * will throw "reference to undefined XML name @a" (or 5, in older - * versions that followed the first edition of ECMA-357 and evaluated - * unbound identifiers to undefined), and the exception must not be - * caught until control unwinds to the outer interpreter activation. - * - * Otherwise, the wrong stack depth will be restored by JSOP_SETSP, - * and the catch will move into the filtering predicate expression, - * leading to double catch execution if it rethrows. - * - * XXX This assumes the null mark case implies XML filtering predicate - * expression execution! - * FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=309894 - */ - if (cx->throwing && JS_LIKELY(mark != NULL)) { - /* - * 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 in script that can catch this exception. - */ - SCRIPT_FIND_CATCH_START(script, pc, pc); - if (pc) { - /* Don't clear cx->throwing to save cx->exception from GC. */ - len = 0; - ok = JS_TRUE; -#if JS_HAS_XML_SUPPORT - foreach = JS_FALSE; -#endif - 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) { -#if JS_HAS_XML_SUPPORT - foreach = JS_FALSE; -#endif - 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. - */ - if (JS_LIKELY(mark != NULL)) { - fp->sp = fp->spbase; - fp->spbase = NULL; - js_FreeRawStack(cx, mark); - } else { - SAVE_SP(fp); - } - -out2: - 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 deleted file mode 100644 index edf70f86f..000000000 --- a/src/dom/js/jsinterp.h +++ /dev/null @@ -1,322 +0,0 @@ -/* -*- 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 */ - JSObject *xmlNamespace; /* null or default xml namespace in E4X */ -}; - -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_COMPILING 0x40 /* frame is being used by compiler */ -#define JSFRAME_COMPILE_N_GO 0x80 /* compiler-and-go mode, can optimize name - references based on scope chain */ -#define JSFRAME_SCRIPT_OBJECT 0x100 /* compiling source for a Script object */ - -#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); - -#ifdef DUMP_CALL_TABLE -# define JSOPTION_LOGCALL_TOSOURCE JS_BIT(15) - -extern JSHashTable *js_CallTable; -extern size_t js_LogCallToSourceLimit; - -extern void js_DumpCallTable(JSContext *cx); -#endif - -/* - * 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. - */ -extern JSBool -js_ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp); - -/* - * NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp - * is non-null), and that the callee, |this| parameter, and actual arguments - * are already pushed on the stack under cx->fp->sp. - */ -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, - JSObject **objp, JSProperty **propp); - -extern JSBool -js_StrictlyEqual(jsval lval, jsval rval); - -extern JSBool -js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result); - -JS_END_EXTERN_C - -#endif /* jsinterp_h___ */ diff --git a/src/dom/js/jslibmath.h b/src/dom/js/jslibmath.h deleted file mode 100644 index 544d8f800..000000000 --- a/src/dom/js/jslibmath.h +++ /dev/null @@ -1,290 +0,0 @@ -/* -*- 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 -#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 WINCE) || 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 deleted file mode 100644 index 968e98b84..000000000 --- a/src/dom/js/jslock.c +++ /dev/null @@ -1,1261 +0,0 @@ -/* -*- 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 -#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 - -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 - -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 -#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; inext = 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; - } - - /* - * If scope->ownercx is not null, it's likely that two contexts not using - * requests nested locks for scope. The first context, cx here, claimed - * scope; the second, scope->ownercx here, re-claimed it because the first - * was not in a request, or was on the same thread. We don't want to keep - * track of such nesting, because it penalizes the common non-nested case. - * Instead of asserting here and silently coping, we simply re-claim scope - * for cx and return. - * - * See http://bugzilla.mozilla.org/show_bug.cgi?id=229200 for a real world - * case where an asymmetric thread model (Mozilla's main thread is known - * to be the only thread that runs the GC) combined with multiple contexts - * per thread has led to such request-less nesting. - */ - if (scope->ownercx) { - JS_ASSERT(scope->u.count == 0); - JS_ASSERT(scope->lock.owner == 0); - scope->ownercx = cx; - return; - } - - 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 deleted file mode 100644 index 0ab71927b..000000000 --- a/src/dom/js/jslock.h +++ /dev/null @@ -1,261 +0,0 @@ -/* -*- 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. - */ -#include "jsscope.h" - -#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))) -#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)) -#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) - -#endif /* jslock_h___ */ diff --git a/src/dom/js/jslocko.asm b/src/dom/js/jslocko.asm deleted file mode 100644 index 95353ba1a..000000000 --- a/src/dom/js/jslocko.asm +++ /dev/null @@ -1,60 +0,0 @@ -; -*- 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 deleted file mode 100644 index 9bfca4dd3..000000000 --- a/src/dom/js/jslog2.c +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 9a4a5b4d7..000000000 --- a/src/dom/js/jslong.c +++ /dev/null @@ -1,281 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 059cf00bb..000000000 --- a/src/dom/js/jslong.h +++ /dev/null @@ -1,437 +0,0 @@ -/* -*- 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_ -** -** 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_ -** -** 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_ -** -** 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_ -** -** 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_ -** -** 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_ -** -** 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 deleted file mode 100644 index 19005eafa..000000000 --- a/src/dom/js/jsmath.c +++ /dev/null @@ -1,479 +0,0 @@ -/* -*- 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 -#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; - 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; - 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; -#if !JS_USE_FDLIBM_MATH - /* - * Because C99 and ECMA specify different behavior for pow(), - * we need to wrap the libm call to make it ECMA compliant. - */ - if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); - return JS_TRUE; - } -#endif - 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 deleted file mode 100644 index b67dba1de..000000000 --- a/src/dom/js/jsmath.h +++ /dev/null @@ -1,55 +0,0 @@ -/* ***** 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 deleted file mode 100644 index 8a5596304..000000000 --- a/src/dom/js/jsnum.c +++ /dev/null @@ -1,1145 +0,0 @@ -/* -*- 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 -#endif -#include -#include -#include -#include -#include -#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) -{ - jsint radix; - JSString *str; - jsdouble d; - const jschar *bp, *ep; - - 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; - } - - str = js_ValueToString(cx, argv[0]); - if (!str) - return JS_FALSE; - /* 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} -}; - -JSClass js_NumberClass = { - "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, &js_NumberClass, 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))", js_NumberClass.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, &js_NumberClass, 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) -{ - char thousandsLength, decimalLength; - const char *numGrouping, *tmpGroup; - JSRuntime *rt; - JSString *numStr, *str; - char *num, *buf, *dec, *end, *tmpSrc, *tmpDest; - int digits, size, remainder, nrepeat; - - /* - * Create the string, move back to bytes to make string twiddling - * a bit easier and so we can insert platform charset seperators. - */ - if (!num_toString(cx, obj, 0, argv, rval)) - return JS_FALSE; - JS_ASSERT(JSVAL_IS_STRING(*rval)); - numStr = JSVAL_TO_STRING(*rval); - num = js_GetStringBytes(numStr); - - /* Find bit before the decimal. */ - dec = strchr(num, '.'); - digits = dec ? dec - num : (int)strlen(num); - end = num + digits; - - rt = cx->runtime; - thousandsLength = strlen(rt->thousandsSeparator); - decimalLength = strlen(rt->decimalSeparator); - - /* Figure out how long resulting string will be. */ - size = digits + (dec ? decimalLength + strlen(dec + 1) : 0); - - numGrouping = tmpGroup = rt->numGrouping; - remainder = digits; - if (*num == '-') - remainder--; - - while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') { - if (*tmpGroup >= remainder) - break; - size += thousandsLength; - remainder -= *tmpGroup; - tmpGroup++; - } - if (*tmpGroup == '\0' && *numGrouping != '\0') { - nrepeat = (remainder - 1) / tmpGroup[-1]; - size += thousandsLength * nrepeat; - remainder -= nrepeat * tmpGroup[-1]; - } else { - nrepeat = 0; - } - tmpGroup--; - - buf = (char *)JS_malloc(cx, size + 1); - if (!buf) - return JS_FALSE; - - tmpDest = buf; - tmpSrc = num; - - while (*tmpSrc == '-' || remainder--) - *tmpDest++ = *tmpSrc++; - while (tmpSrc < end) { - strcpy(tmpDest, rt->thousandsSeparator); - tmpDest += thousandsLength; - memcpy(tmpDest, tmpSrc, *tmpGroup); - tmpDest += *tmpGroup; - tmpSrc += *tmpGroup; - if (--nrepeat < 0) - tmpGroup--; - } - - if (dec) { - strcpy(tmpDest, rt->decimalSeparator); - tmpDest += decimalLength; - strcpy(tmpDest, dec + 1); - } else { - *tmpDest++ = '\0'; - } - - str = JS_NewString(cx, buf, size); - if (!str) { - JS_free(cx, buf); - return JS_FALSE; - } - - *rval = STRING_TO_JSVAL(str); - - return JS_TRUE; -} - -static JSBool -num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if (!JS_InstanceOf(cx, obj, &js_NumberClass, 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, &js_NumberClass, 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 XP_OS2) && \ - !defined WINCE && \ - !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; - struct lconv *locale; - - 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, GCF_LOCK); - if (!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, GCF_LOCK); - if (!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, GCF_LOCK); - if (!rt->jsNegativeInfinity) - return JS_FALSE; - - u.s.hi = 0; - u.s.lo = 1; - number_constants[NC_MIN_VALUE].dval = u.d; - - locale = localeconv(); - rt->thousandsSeparator = - JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'"); - rt->decimalSeparator = - JS_strdup(cx, locale->decimal_point ? locale->decimal_point : "."); - rt->numGrouping = - JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0"); - - return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping; -} - -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; - - JS_free(cx, (void *)rt->thousandsSeparator); - JS_free(cx, (void *)rt->decimalSeparator); - JS_free(cx, (void *)rt->numGrouping); - rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = 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, &js_NumberClass, 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, uintN gcflag) -{ - jsdouble *dp; - - dp = (jsdouble *) js_NewGCThing(cx, gcflag | GCX_DOUBLE, sizeof(jsdouble)); - 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, 0); - if (!dp) - return JS_FALSE; - *rval = DOUBLE_TO_JSVAL(dp); - return JS_TRUE; -} - -JSBool -js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval) -{ - jsint i; - - if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) { - *rval = INT_TO_JSVAL(i); - } else { - if (!js_NewDoubleValue(cx, d, rval)) - return JS_FALSE; - } - return JS_TRUE; -} - -JSObject * -js_NumberToObject(JSContext *cx, jsdouble d) -{ - JSObject *obj; - jsval v; - - obj = js_NewObject(cx, &js_NumberClass, 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 deleted file mode 100644 index cd99501e7..000000000 --- a/src/dom/js/jsnum.h +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- 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 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)))) - -#if defined(XP_WIN) -#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) \ - ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL)) \ - ? (IFNAN) \ - : (LVAL) OP (RVAL)) -#else -#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL)) -#endif - -/* 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 JSClass js_NumberClass; - -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, uintN gcflag); - -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); - -JS_END_EXTERN_C - -#endif /* jsnum_h___ */ diff --git a/src/dom/js/jsobj.c b/src/dom/js/jsobj.c deleted file mode 100644 index 03a598094..000000000 --- a/src/dom/js/jsobj.c +++ /dev/null @@ -1,4646 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=78: - * - * ***** 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 -#include -#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 */ - -#if JS_HAS_XML_SUPPORT -#include "jsxml.h" -#endif - -#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 - -JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = { - js_NewObjectMap, js_DestroyObjectMap, - js_LookupProperty, js_DefineProperty, - 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 -}; - -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; - jsid propid; - JSAccessMode mode; - uintN attrs; - JSObject *pobj; - JSClass *clasp; - JSExtendedClass *xclasp; - - slot = (uint32) JSVAL_TO_INT(id); - if (id == INT_TO_JSVAL(JSSLOT_PROTO)) { - propid = ATOM_TO_JSID(cx->runtime->atomState.protoAtom); - mode = JSACC_PROTO; - } else { - propid = ATOM_TO_JSID(cx->runtime->atomState.parentAtom); - mode = JSACC_PARENT; - } - - /* Let OBJ_CHECK_ACCESS get the slot's value, based on the access mode. */ - if (!OBJ_CHECK_ACCESS(cx, obj, propid, mode, vp, &attrs)) - return JS_FALSE; - - pobj = JSVAL_TO_OBJECT(*vp); - if (pobj) { - clasp = OBJ_GET_CLASS(cx, pobj); - if (clasp->flags & JSCLASS_IS_EXTENDED) { - xclasp = (JSExtendedClass *) clasp; - if (xclasp->outerObject) { - pobj = xclasp->outerObject(cx, pobj); - if (!pobj) - return JS_FALSE; - *vp = OBJECT_TO_JSVAL(pobj); - } - } - } - return JS_TRUE; -} - -static JSBool -obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSObject *pobj; - uint32 slot; - jsid propid; - 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. */ - propid = ATOM_TO_JSID(cx->runtime->atomState.protoAtom); - if (!OBJ_CHECK_ACCESS(cx, obj, propid, 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)JS_PTR_TO_UINT32(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; - int stackDummy; - - if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); - return NULL; - } - - 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, - JS_UINT32_TO_PTR(sharpid)); - if (!he) { - JS_ReportOutOfMemory(cx); - return NULL; - } - - /* - * Increment map->depth to protect js_EnterSharpObject from reentering - * itself badly. Without this fix, if we reenter the basis case where - * map->depth == 0, when unwinding the inner call we will destroy the - * newly-created hash table and crash. - */ - ++map->depth; - ida = JS_Enumerate(cx, obj); - --map->depth; - 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) - continue; - 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 = JS_PTR_TO_UINT32(he->value); - if (sharpid == 0) { - sharpid = ++map->sharpgen << SHARP_ID_SHIFT; - he->value = JS_UINT32_TO_PTR(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; - - if (JS_HAS_NATIVE_BRANCH_CALLBACK_OPTION(cx) && - cx->branchCallback && - !cx->branchCallback(cx, NULL)) { - return NULL; - } - - /* 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; - JS_KEEP_ATOMS(cx->runtime); - } - - /* From this point the control must flow either through out: or bad:. */ - ida = NULL; - if (map->depth == 0) { - he = MarkSharpObjects(cx, obj, &ida); - if (!he) - goto bad; - JS_ASSERT((JS_PTR_TO_UINT32(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; - } - sharpid = 0; - goto out; - } - } - - sharpid = JS_PTR_TO_UINT32(he->value); - if (sharpid != 0) { - 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) { - JS_UNKEEP_ATOMS(cx->runtime); - 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) { - JS_UNKEEP_ATOMS(cx->runtime); - map->sharpgen = 0; - JS_HashTableDestroy(map->table); - map->table = NULL; - } - if (idap) { - ida = *idap; - if (ida) { - JS_DestroyIdArray(cx, ida); - *idap = NULL; - } - } -} - -JS_STATIC_DLL_CALLBACK(intN) -gc_sharp_table_entry_marker(JSHashEntry *he, intN i, void *arg) -{ - GC_MARK((JSContext *)arg, (JSObject *)he->key, "sharp table entry", NULL); - return JS_DHASH_NEXT; -} - -void -js_GCMarkSharpMap(JSContext *cx, JSSharpObjectMap *map) -{ - JS_ASSERT(map->depth > 0); - JS_ASSERT(map->table); - - /* - * During recursive calls to MarkSharpObjects a non-native object or - * object with a custom getProperty method can potentially return an - * unrooted value or even cut from the object graph an argument of one of - * MarkSharpObjects recursive invocations. So we must protect map->table - * entries against GC. - * - * We can not simply use JSTempValueRooter to mark the obj argument of - * MarkSharpObjects during recursion as we have to protect *all* entries - * in JSSharpObjectMap including those that contains otherwise unreachable - * objects just allocated through custom getProperty. Otherwise newer - * allocations can re-use the address of an object stored in the hashtable - * confusing js_EnterSharpObject. So to address the problem we simply - * mark all objects from map->table. - * - * An alternative "proper" solution is to use JSTempValueRooter in - * MarkSharpObjects with code to remove during finalization entries - * with otherwise unreachable objects. But this is way too complex - * to justify spending efforts. - */ - JS_HashTableEnumerateEntries(map->table, gc_sharp_table_entry_marker, cx); -} - -#define OBJ_TOSTRING_EXTRA 4 /* for 4 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, curlen; - char *comma; - jsint i, j, length, valcnt; - jsid id; -#if JS_HAS_GETTER_SETTER - JSObject *obj2; - JSProperty *prop; - uintN attrs; -#endif - jsval *val; - 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 = !JS_VERSION_IS_1_2(cx) && 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; - } - } - -#ifdef DUMP_CALL_TABLE - if (cx->options & JSOPTION_LOGCALL_TOSOURCE) { - const char *classname = OBJ_GET_CLASS(cx, obj)->name; - size_t classnchars = strlen(classname); - static const char classpropid[] = "C"; - const char *cp; - size_t onchars = nchars; - - /* 2 for ': ', 2 quotes around classname, 2 for ', ' after. */ - classnchars += sizeof classpropid - 1 + 2 + 2; - if (ida->length) - classnchars += 2; - - /* 2 for the braces, 1 for the terminator */ - chars = (jschar *) - realloc((ochars = chars), - (nchars + classnchars + 2 + 1) * sizeof(jschar)); - if (!chars) { - free(ochars); - goto error; - } - - chars[nchars++] = '{'; /* 1 from the 2 braces */ - for (cp = classpropid; *cp; cp++) - chars[nchars++] = (jschar) *cp; - chars[nchars++] = ':'; - chars[nchars++] = ' '; /* 2 for ': ' */ - chars[nchars++] = '"'; - for (cp = classname; *cp; cp++) - chars[nchars++] = (jschar) *cp; - chars[nchars++] = '"'; /* 2 quotes */ - if (ida->length) { - chars[nchars++] = ','; - chars[nchars++] = ' '; /* 2 for ', ' */ - } - - JS_ASSERT(nchars - onchars == 1 + classnchars); - } else -#endif - chars[nchars++] = '{'; - - comma = NULL; - - /* - * We have four local roots for cooked and raw value GC safety. Hoist the - * "argv + 2" out of the loop using the val local, which refers to the raw - * (unconverted, "uncooked") values. - */ - val = argv + 2; - - 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 = JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL; - id = ID_TO_VALUE(id); - idstr = js_ValueToString(cx, id); - if (!idstr) { - ok = JS_FALSE; - goto error; - } - *rval = STRING_TO_JSVAL(idstr); /* local root */ - - /* - * 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. Also, negative - * integer ids must be quoted. - */ - if (atom - ? (ATOM_KEYWORD(atom) || !js_IsIdentifier(idstr)) - : (JSID_IS_OBJECT(id) || JSID_TO_INT(id) < 0)) { - idstr = js_QuoteString(cx, idstr, (jschar)'\''); - if (!idstr) { - ok = JS_FALSE; - goto error; - } - *rval = STRING_TO_JSVAL(idstr); /* local root */ - } - 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[j] = STRING_TO_JSVAL(valstr); /* local root */ - vchars = JSSTRING_CHARS(valstr); - vlength = JSSTRING_LENGTH(valstr); - -#ifndef OLD_GETTER_SETTER - /* - * Remove '(function ' from the beginning of valstr and ')' from the - * end so that we can put "get" in front of the function definition. - */ - if (gsop[j]) { - int n = strlen(js_function_str) + 2; - vchars += n; - vlength -= n + 1; - } -#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 - -#define SAFE_ADD(n) \ - JS_BEGIN_MACRO \ - size_t n_ = (n); \ - curlen += n_; \ - if (curlen < n_) \ - goto overflow; \ - JS_END_MACRO - - curlen = nchars; - if (comma) - SAFE_ADD(2); - SAFE_ADD(idstrlength + 1); - if (gsop[j]) - SAFE_ADD(JSSTRING_LENGTH(gsop[j]) + 1); - SAFE_ADD(vsharplength); - SAFE_ADD(vlength); - SAFE_ADD((outermost ? 2 : 1) + 1); -#undef SAFE_ADD - - if (curlen > (size_t)-1 / sizeof(jschar)) - goto overflow; - - /* Allocate 1 + 1 at end for closing brace and terminating 0. */ - chars = (jschar *) - realloc((ochars = chars), curlen * 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); -#ifdef DUMP_CALL_TABLE - if (outermost && nchars >= js_LogCallToSourceLimit) - break; -#endif - } - } - - 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; - - overflow: - JS_free(cx, vsharp); - free(chars); - chars = NULL; - goto error; -} -#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 (JS_VERSION_IS_1_2(cx)) - 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 -js_obj_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSString *str; - - str = js_ValueToString(cx, argv[-1]); - if (!str) - 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; -} - -/* - * Check whether principals subsumes scopeobj's principals, and return true - * if so (or if scopeobj has no principals, for backward compatibility with - * the JS API, which does not require principals), and false otherwise. - */ -JSBool -js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj, - JSPrincipals *principals, const char *caller) -{ - JSRuntime *rt; - JSPrincipals *scopePrincipals; - - rt = cx->runtime; - if (rt->findObjectPrincipals) { - scopePrincipals = rt->findObjectPrincipals(cx, scopeobj); - if (!principals || !scopePrincipals || - !principals->subsume(principals, scopePrincipals)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_INDIRECT_CALL, caller); - return JS_FALSE; - } - } - return JS_TRUE; -} - -JSObject * -js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller) -{ - JSClass *clasp; - JSExtendedClass *xclasp; - JSObject *inner; - - if (!scopeobj) - goto bad; - - OBJ_TO_INNER_OBJECT(cx, scopeobj); - if (!scopeobj) - return NULL; - - inner = scopeobj; - - /* XXX This is an awful gross hack. */ - while (scopeobj) { - clasp = OBJ_GET_CLASS(cx, scopeobj); - if (clasp->flags & JSCLASS_IS_EXTENDED) { - xclasp = (JSExtendedClass*)clasp; - if (xclasp->innerObject && - xclasp->innerObject(cx, scopeobj) != scopeobj) { - goto bad; - } - } - - scopeobj = OBJ_GET_PARENT(cx, scopeobj); - } - - return inner; - -bad: - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_INDIRECT_CALL, caller); - return NULL; -} - -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; - JSObject *setCallerScopeChain = NULL; - JSBool setCallerVarObj = JS_FALSE; -#endif - - fp = cx->fp; - caller = JS_GetScriptedCaller(cx, fp); - indirectCall = (caller && caller->pc && *caller->pc != JSOP_EVAL); - - if (JS_VERSION_IS_ECMA(cx) && - 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 the caller is a lightweight function and doesn't have a variables - * object, then we need to provide one for the compiler to stick any - * declared (var) variables into. - */ - if (caller && !caller->varobj && !js_GetCallObject(cx, caller, NULL)) - return JS_FALSE; - -#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) { - if (!js_CheckPrincipalsAccess(cx, obj, - caller->script->principals, - js_eval_str)) { - return JS_FALSE; - } - - scopeobj = js_NewWithObject(cx, obj, callerScopeChain, -1); - if (!scopeobj) - return JS_FALSE; - - /* Set fp->scopeChain too, for the compiler. */ - caller->scopeChain = fp->scopeChain = scopeobj; - - /* Remember scopeobj so we can null its private when done. */ - setCallerScopeChain = scopeobj; - } - - 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 - } - - /* Ensure we compile this eval with the right object in the scope chain. */ - scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_eval_str); - if (!scopeobj) - return JS_FALSE; - - 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; - } - - /* - * Set JSFRAME_EVAL on fp and any frames (e.g., fun_call if eval.call was - * invoked) between fp and its scripted caller, to help the compiler easily - * find the same caller whose scope and var obj we've set. - * - * XXX this nonsense could, and perhaps should, go away with a better way - * to pass params to the compiler than via the top-most frame. - */ - do { - fp->flags |= JSFRAME_EVAL; - } while ((fp = fp->down) != caller); - - 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 - - /* - * Belt-and-braces: check that the lesser of eval's principals and the - * caller's principals has access to scopeobj. - */ - ok = js_CheckPrincipalsAccess(cx, scopeobj, principals, js_eval_str); - if (ok) - 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; - JS_ASSERT(OBJ_GET_CLASS(cx, setCallerScopeChain) == &js_WithClass); - JS_SetPrivate(cx, setCallerScopeChain, NULL); - } - if (setCallerVarObj) - caller->varobj = callerVarObj; -#endif - return ok; -} - -#if JS_HAS_OBJ_WATCHPOINT - -static JSBool -obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp, - void *closure) -{ - JSObject *callable; - JSRuntime *rt; - JSStackFrame *caller; - JSPrincipals *subject, *watcher; - JSResolvingKey key; - JSResolvingEntry *entry; - uint32 generation; - jsval argv[3]; - JSBool ok; - - callable = (JSObject *) closure; - - rt = cx->runtime; - if (rt->findObjectPrincipals) { - /* Skip over any obj_watch_* frames between us and the real subject. */ - caller = JS_GetScriptedCaller(cx, cx->fp); - if (caller) { - /* - * Only call the watch handler if the watcher is allowed to watch - * the currently executing script. - */ - watcher = rt->findObjectPrincipals(cx, callable); - subject = JS_StackFramePrincipals(cx, caller); - - if (watcher && subject && !watcher->subsume(watcher, subject)) { - /* Silently don't call the watch handler. */ - return JS_TRUE; - } - } - } - - /* Avoid recursion on (obj, id) already being watched on cx. */ - key.obj = obj; - key.id = id; - if (!js_StartResolving(cx, &key, JSRESFLAG_WATCH, &entry)) - return JS_FALSE; - if (!entry) - return JS_TRUE; - generation = cx->resolvingTable->generation; - - argv[0] = id; - argv[1] = old; - argv[2] = *nvp; - ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(callable), 3, argv, nvp); - js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation); - return ok; -} - -static JSBool -obj_watch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSObject *callable; - jsval userid, value; - jsid propid; - uintN attrs; - - callable = js_ValueToCallableObject(cx, &argv[1], 0); - if (!callable) - return JS_FALSE; - - /* 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, callable); -} - -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) -{ - return js_HasOwnPropertyHelper(cx, obj, obj->map->ops->lookupProperty, - argc, argv, rval); -} - -JSBool -js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, - 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 (!lookup(cx, obj, id, &obj2, &prop)) - return JS_FALSE; - if (!prop) { - *rval = JSVAL_FALSE; - } else if (obj2 == obj) { - *rval = JSVAL_TRUE; - } else { - JSClass *clasp; - JSExtendedClass *xclasp; - - clasp = OBJ_GET_CLASS(cx, obj); - xclasp = (clasp->flags & JSCLASS_IS_EXTENDED) - ? (JSExtendedClass *)clasp - : NULL; - if (xclasp && xclasp->outerObject && - xclasp->outerObject(cx, obj2) == obj) { - *rval = JSVAL_TRUE; - } else if (OBJ_IS_NATIVE(obj2) && OBJ_GET_CLASS(cx, obj2) == clasp) { - /* - * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a - * delegated property makes that property appear to be direct in - * all delegating instances of the same native class. This hack - * avoids bloating every function instance with its own 'length' - * (AKA 'arity') property. But it must not extend across class - * boundaries, to avoid making hasOwnProperty lie (bug 320854). - * - * It's not really a hack, of course: a permanent property can't - * be deleted, and JSPROP_SHARED means "don't allocate a slot in - * any instance, prototype or delegating". Without a slot, and - * without the ability to remove and recreate (with differences) - * the property, there is no way to tell whether it is directly - * owned, or indirectly delegated. - */ - 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; - 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, NULL, NULL)) - 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_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED, - NULL); -} - -static JSBool -obj_defineSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsval fval, junk; - jsid id; - 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, NULL, NULL)) - 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_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED, - NULL); -} - -static JSBool -obj_lookupGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsid id; - JSObject *pobj; - JSProperty *prop; - JSScopeProperty *sprop; - - if (!JS_ValueToId(cx, argv[0], &id)) - return JS_FALSE; - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) - return JS_FALSE; - if (prop) { - if (OBJ_IS_NATIVE(pobj)) { - sprop = (JSScopeProperty *) prop; - if (sprop->attrs & JSPROP_GETTER) - *rval = OBJECT_TO_JSVAL(sprop->getter); - } - OBJ_DROP_PROPERTY(cx, pobj, prop); - } - return JS_TRUE; -} - -static JSBool -obj_lookupSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsid id; - JSObject *pobj; - JSProperty *prop; - JSScopeProperty *sprop; - - if (!JS_ValueToId(cx, argv[0], &id)) - return JS_FALSE; - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) - return JS_FALSE; - if (prop) { - if (OBJ_IS_NATIVE(pobj)) { - sprop = (JSScopeProperty *) prop; - if (sprop->attrs & JSPROP_SETTER) - *rval = OBJECT_TO_JSVAL(sprop->setter); - } - OBJ_DROP_PROPERTY(cx, pobj, prop); - } - 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_toLocaleString, 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) -{ - JSObject *proto = OBJ_GET_PROTO(cx, obj); - if (!proto) - return js_LookupProperty(cx, obj, id, objp, propp); - return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp); -} - -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", - JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1), - 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 -}; - -JSObject * -js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth) -{ - JSObject *obj; - - obj = js_NewObject(cx, &js_WithClass, proto, parent); - if (!obj) - return NULL; - obj->slots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(cx->fp); - OBJ_SET_BLOCK_DEPTH(cx, obj, depth); - return obj; -} - -#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_NewWithObject(cx, NULL, NULL, -1); - 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, - ATOM_TO_JSID(cx->runtime->atomState.evalAtom), - &eval)) { - return NULL; - } - if (!OBJ_DEFINE_PROPERTY(cx, obj, - ATOM_TO_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); - -static jsval * -AllocSlots(JSContext *cx, jsval *slots, uint32 nslots) -{ - size_t nbytes, obytes, minbytes; - uint32 i, oslots; - jsval *newslots; - - nbytes = (nslots + 1) * sizeof(jsval); - if (slots) { - oslots = slots[-1]; - obytes = (oslots + 1) * sizeof(jsval); - } else { - oslots = 0; - obytes = 0; - } - - if (nbytes <= GC_NBYTES_MAX) { - newslots = (jsval *) js_NewGCThing(cx, GCX_PRIVATE, nbytes); - } else { - newslots = (jsval *) - JS_realloc(cx, - (obytes <= GC_NBYTES_MAX) ? NULL : slots - 1, - nbytes); - } - if (!newslots) - return NULL; - - if (obytes != 0) { - /* If either nbytes or obytes fit in a GC-thing, we must copy. */ - minbytes = JS_MIN(nbytes, obytes); - if (minbytes <= GC_NBYTES_MAX) - memcpy(newslots + 1, slots, minbytes - sizeof(jsval)); - - /* If nbytes are in a GC-thing but obytes aren't, free obytes. */ - if (nbytes <= GC_NBYTES_MAX && obytes > GC_NBYTES_MAX) - JS_free(cx, slots - 1); - - /* If we're extending an allocation, initialize free slots. */ - if (nslots > oslots) { - for (i = 1 + oslots; i <= nslots; i++) - newslots[i] = JSVAL_VOID; - } - } - - newslots[0] = nslots; - return ++newslots; -} - -static void -FreeSlots(JSContext *cx, jsval *slots) -{ - size_t nbytes; - - /* - * NB: We count on smaller GC-things being finalized before larger things - * that become garbage during the same GC. Without this assumption, we - * couldn't load slots[-1] here without possibly loading a gcFreeList link - * (see struct JSGCThing in jsgc.h). - */ - nbytes = (slots[-1] + 1) * sizeof(jsval); - if (nbytes > GC_NBYTES_MAX) - JS_free(cx, slots - 1); -} - -JSObject * -js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) -{ - JSObject *obj; - JSObjectOps *ops; - JSObjectMap *map; - JSClass *protoclasp; - uint32 nslots, i; - jsval *newslots; - JSTempValueRooter tvr; - - /* Bootstrap the ur-object, and make it the default prototype object. */ - if (!proto) { - if (!GetClassPrototype(cx, parent, clasp->name, &proto)) - return NULL; - if (!proto && !GetClassPrototype(cx, parent, js_Object_str, &proto)) - return NULL; - } - - /* Always call the class's getObjectOps hook if it has one. */ - ops = clasp->getObjectOps - ? clasp->getObjectOps(cx, clasp) - : &js_ObjectOps; - - /* - * Allocate a zeroed object from the GC heap. Do this *after* any other - * GC-thing allocations under GetClassPrototype or clasp->getObjectOps, - * to avoid displacing the newborn root for obj. - */ - obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject)); - if (!obj) - return NULL; - - /* - * Root obj to prevent it from being killed. - * AllocSlots can trigger a finalizer from a last-ditch GC calling - * JS_ClearNewbornRoots. There's also the possibilty of things - * happening under the objectHook call-out below. - */ - JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(obj), &tvr); - - /* - * 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. We assume that if prototype and object are of the - * same class, they always have the same number of computed reserved - * slots (returned via clasp->reserveSlots); otherwise, prototype and - * object classes must have the same (null or not) reserveSlots hook. - */ - if (proto && - (map = proto->map)->ops == ops && - ((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp || - (!((protoclasp->flags ^ clasp->flags) & - (JSCLASS_HAS_PRIVATE | - (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) && - protoclasp->reserveSlots == clasp->reserveSlots))) - { - /* - * Default parent to the parent of the prototype, which was set from - * the parent of the prototype's constructor. - */ - if (!parent) - parent = OBJ_GET_PARENT(cx, proto); - - /* 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 = AllocSlots(cx, NULL, nslots); - if (!newslots) { - js_DropObjectMap(cx, obj->map, obj); - obj->map = NULL; - goto bad; - } - - /* 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) { - JS_KEEP_ATOMS(cx->runtime); - cx->runtime->objectHook(cx, obj, JS_TRUE, cx->runtime->objectHookData); - JS_UNKEEP_ATOMS(cx->runtime); - } - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - cx->newborn[GCX_OBJECT] = (JSGCThing *) obj; - return obj; - -bad: - obj = NULL; - goto out; -} - -JSBool -js_FindConstructor(JSContext *cx, JSObject *start, const char *name, jsval *vp) -{ - JSAtom *atom; - JSObject *obj, *pobj; - JSProperty *prop; - JSScopeProperty *sprop; - - atom = js_Atomize(cx, name, strlen(name), 0); - if (!atom) - return JS_FALSE; - - if (start || (cx->fp && (start = cx->fp->scopeChain) != NULL)) { - /* Find the topmost object in the scope chain. */ - do { - obj = start; - start = OBJ_GET_PARENT(cx, obj); - } while (start); - } else { - obj = cx->globalObject; - if (!obj) { - *vp = JSVAL_VOID; - return JS_TRUE; - } - } - - JS_ASSERT(OBJ_IS_NATIVE(obj)); - if (!js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom), - JSRESOLVE_CLASSNAME, &pobj, &prop)) { - return JS_FALSE; - } - if (!prop) { - *vp = JSVAL_VOID; - return JS_TRUE; - } - - JS_ASSERT(OBJ_IS_NATIVE(pobj)); - sprop = (JSScopeProperty *) prop; - JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))); - *vp = OBJ_GET_SLOT(cx, pobj, sprop->slot); - OBJ_DROP_PROPERTY(cx, pobj, prop); - return JS_TRUE; -} - -JSObject * -js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, - JSObject *parent, uintN argc, jsval *argv) -{ - jsval cval, rval; - JSTempValueRooter argtvr, tvr; - JSObject *obj, *ctor; - - JS_PUSH_TEMP_ROOT(cx, argc, argv, &argtvr); - - if (!js_FindConstructor(cx, parent, clasp->name, &cval)) { - JS_POP_TEMP_ROOT(cx, &argtvr); - return NULL; - } - if (JSVAL_IS_PRIMITIVE(cval)) { - js_ReportIsNotFunction(cx, &cval, JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK); - JS_POP_TEMP_ROOT(cx, &argtvr); - return NULL; - } - - /* - * Protect cval in case a crazy getter for .prototype uproots it. After - * this point, all control flow must exit through label out with obj set. - */ - JS_PUSH_SINGLE_TEMP_ROOT(cx, cval, &tvr); - - /* - * 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, - ATOM_TO_JSID(cx->runtime->atomState - .classPrototypeAtom), - &rval)) { - obj = NULL; - goto out; - } - if (JSVAL_IS_OBJECT(rval)) - proto = JSVAL_TO_OBJECT(rval); - } - - obj = js_NewObject(cx, clasp, proto, parent); - if (!obj) - goto out; - - if (!js_InternalConstruct(cx, obj, cval, argc, argv, &rval)) - goto bad; - - if (JSVAL_IS_PRIMITIVE(rval)) - goto out; - obj = JSVAL_TO_OBJECT(rval); - - /* - * If the given class has both the JSCLASS_HAS_PRIVATE and the - * JSCLASS_CONSTRUCT_PROTOTYPE flags, then the class should have its private - * data set. If it doesn't, then it means the constructor was replaced, and - * we should throw a typerr. - */ - if (OBJ_GET_CLASS(cx, obj) != clasp || - (!(~clasp->flags & (JSCLASS_HAS_PRIVATE | - JSCLASS_CONSTRUCT_PROTOTYPE)) && - !JS_GetPrivate(cx, obj))) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_WRONG_CONSTRUCTOR, clasp->name); - goto bad; - } - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - JS_POP_TEMP_ROOT(cx, &argtvr); - return obj; - -bad: - cx->newborn[GCX_OBJECT] = NULL; - obj = NULL; - goto out; -} - -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; - FreeSlots(cx, obj->slots); - 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; - JSClass *clasp; - uint32 nslots; - jsval *newslots; - - map = obj->map; - JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj); - clasp = LOCKED_OBJ_GET_CLASS(obj); - if (map->freeslot == JSSLOT_FREE(clasp)) { - /* Adjust map->freeslot to include computed reserved slots, if any. */ - if (clasp->reserveSlots) - map->freeslot += clasp->reserveSlots(cx, obj); - } - nslots = map->nslots; - if (map->freeslot >= nslots) { - nslots = map->freeslot; - JS_ASSERT(nslots >= JS_INITIAL_NSLOTS); - nslots += (nslots + 1) / 2; - - newslots = AllocSlots(cx, obj->slots, nslots); - if (!newslots) - return JS_FALSE; - map->nslots = nslots; - obj->slots = newslots; - } - -#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; - 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; - - newslots = AllocSlots(cx, obj->slots, nslots); - if (!newslots) - return; - map->nslots = nslots; - obj->slots = newslots; - } -} - -#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_STRING_INDEX(id) \ - JS_BEGIN_MACRO \ - if (JSID_IS_ATOM(id)) { \ - JSAtom *atom_ = JSID_TO_ATOM(id); \ - JSString *str_ = ATOM_TO_STRING(atom_); \ - const jschar *cp_ = str_->chars; \ - JSBool negative_ = (*cp_ == '-'); \ - if (negative_) cp_++; \ - if (JS7_ISDEC(*cp_)) { \ - size_t n_ = str_->length - negative_; \ - if (n_ <= sizeof(JSVAL_INT_MAX_STRING) - 1) \ - id = CheckForStringIndex(id, cp_, cp_ + n_, negative_); \ - } else { \ - CHECK_FOR_EMPTY_INDEX(id); \ - } \ - } \ - JS_END_MACRO - -static jsid -CheckForStringIndex(jsid id, const jschar *cp, const jschar *end, - 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 == end && - (oldIndex < (JSVAL_INT_MAX / 10) || - (oldIndex == (JSVAL_INT_MAX / 10) && - c <= (JSVAL_INT_MAX % 10)))) { - if (negative) - index = 0 - index; - id = INT_TO_JSID((jsint)index); - } - return id; -} - -static JSBool -HidePropertyName(JSContext *cx, jsid *idp) -{ - jsid id; - JSAtom *atom, *hidden; - - id = *idp; - JS_ASSERT(JSID_IS_ATOM(id)); - - atom = JSID_TO_ATOM(id); - JS_ASSERT(!(atom->flags & ATOM_HIDDEN)); - JS_ASSERT(ATOM_IS_STRING(atom)); - - hidden = js_AtomizeString(cx, ATOM_TO_STRING(atom), ATOM_HIDDEN); - if (!hidden) - return JS_FALSE; - - /* - * Link hidden to unhidden atom to optimize call_enumerate -- this means - * the GC must mark a hidden atom's unhidden counterpart (see js_MarkAtom - * in jsgc.c). It overloads the entry.value member, which for unhidden - * atoms may point to keyword information. - */ - hidden->entry.value = atom; - *idp = ATOM_TO_JSID(hidden); - return JS_TRUE; -} - -JSScopeProperty * -js_AddHiddenProperty(JSContext *cx, JSObject *obj, jsid id, - JSPropertyOp getter, JSPropertyOp setter, uint32 slot, - uintN attrs, uintN flags, intN shortid) -{ - if (!HidePropertyName(cx, &id)) - return NULL; - - flags |= SPROP_IS_HIDDEN; - return js_AddNativeProperty(cx, obj, id, getter, setter, slot, attrs, - flags, shortid); -} - -JSBool -js_LookupHiddenProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, - JSProperty **propp) -{ - return HidePropertyName(cx, &id) && - js_LookupProperty(cx, obj, id, objp, propp); -} - -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_STRING_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); -} - -/* - * Backward compatibility requires allowing addProperty hooks to mutate the - * nominal initial value of a slot-full property, while GC safety wants that - * value to be stored before the call-out through the hook. Optimize to do - * both while saving cycles for classes that stub their addProperty hook. - */ -#define ADD_PROPERTY_HELPER(cx,clasp,obj,scope,sprop,vp,cleanup) \ - JS_BEGIN_MACRO \ - if ((clasp)->addProperty != JS_PropertyStub) { \ - jsval nominal_ = *(vp); \ - if (!(clasp)->addProperty(cx, obj, SPROP_USERID(sprop), vp)) { \ - cleanup; \ - } \ - if (*(vp) != nominal_) { \ - if (SPROP_HAS_VALID_SLOT(sprop, scope)) \ - LOCKED_OBJ_SET_SLOT(obj, (sprop)->slot, *(vp)); \ - } \ - } \ - JS_END_MACRO - -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; - JSProperty *prop; - JSScopeProperty *sprop; - - /* - * Handle old bug that took empty string as zero index. Also convert - * string indices to integers if appropriate. - */ - CHECK_FOR_STRING_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, &prop)) - return JS_FALSE; - sprop = (JSScopeProperty *) prop; - 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 (prop) { - /* NB: call OBJ_DROP_PROPERTY, as pobj might not be native. */ - OBJ_DROP_PROPERTY(cx, pobj, prop); - prop = 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; - - /* Store value before calling addProperty, in case the latter GC's. */ - if (SPROP_HAS_VALID_SLOT(sprop, scope)) - LOCKED_OBJ_SET_SLOT(obj, sprop->slot, value); - - /* XXXbe called with lock held */ - ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value, - js_RemoveScopeProperty(cx, scope, id); - goto bad); - -#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; -} - -/* - * Given pc pointing after a property accessing bytecode, return true if the - * access is a "object-detecting" in the sense used by web pages, e.g., when - * checking whether document.all is defined. - */ -static JSBool -Detecting(JSContext *cx, jsbytecode *pc) -{ - JSScript *script; - jsbytecode *endpc; - JSOp op; - JSAtom *atom; - - if (!cx->fp) - return JS_FALSE; - script = cx->fp->script; - for (endpc = script->code + script->length; pc < endpc; pc++) { - /* General case: a branch or equality op follows the access. */ - op = (JSOp) *pc; - if (js_CodeSpec[op].format & JOF_DETECTING) - return JS_TRUE; - - /* - * Special case #1: handle (document.all == null). Don't sweat about - * JS1.2's revision of the equality operators here. - */ - if (op == JSOP_NULL) { - if (++pc < endpc) - return *pc == JSOP_EQ || *pc == JSOP_NE; - break; - } - - /* - * Special case #2: handle (document.all == undefined). Don't worry - * about someone redefining undefined, which was added by Edition 3, - * so was read/write for backward compatibility. - */ - if (op == JSOP_NAME) { - atom = GET_ATOM(cx, script, pc); - if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] && - (pc += js_CodeSpec[op].length) < endpc) { - op = (JSOp) *pc; - return op == JSOP_EQ || op == JSOP_NE || - op == JSOP_NEW_EQ || op == JSOP_NEW_NE; - } - break; - } - - /* At this point, anything but grouping means we're not detecting. */ - if (op != JSOP_GROUP) - break; - } - return JS_FALSE; -} - -JS_FRIEND_API(JSBool) -js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, - JSProperty **propp) -{ - return js_LookupPropertyWithFlags(cx, obj, id, 0, objp, propp); -} - -JSBool -js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, - JSObject **objp, JSProperty **propp) -{ - JSObject *start, *obj2, *proto; - JSScope *scope; - JSScopeProperty *sprop; - JSClass *clasp; - JSResolveOp resolve; - JSResolvingKey key; - JSResolvingEntry *entry; - uint32 generation; - JSNewResolveOp newresolve; - jsbytecode *pc; - const JSCodeSpec *cs; - uint32 format; - JSBool ok; - - /* - * Handle old bug that took empty string as zero index. Also convert - * string indices to integers if appropriate. - */ - CHECK_FOR_STRING_INDEX(id); - - /* Search scopes starting with obj and following the prototype link. */ - start = obj; - for (;;) { - JS_LOCK_OBJ(cx, obj); - 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 (!js_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; - if (!(flags & JSRESOLVE_CLASSNAME) && - cx->fp && - (pc = cx->fp->pc)) { - cs = &js_CodeSpec[*pc]; - format = cs->format; - if ((format & JOF_MODEMASK) != JOF_NAME) - flags |= JSRESOLVE_QUALIFIED; - if ((format & JOF_ASSIGNING) || - (cx->fp->flags & JSFRAME_ASSIGNING)) { - flags |= JSRESOLVE_ASSIGNING; - } else { - pc += cs->length; - if (Detecting(cx, pc)) - flags |= JSRESOLVE_DETECTING; - } - if (format & JOF_DECLARING) - flags |= JSRESOLVE_DECLARING; - } - 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); - 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 (sprop) { - JS_ASSERT(obj2 == scope->object); - obj = obj2; - } else if (obj2 != obj) { - 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); - scope = OBJ_SCOPE(obj); - JS_ASSERT(MAP_IS_NATIVE(&scope->map)); - if (scope->object == obj) - sprop = SCOPE_GET_PROPERTY(scope, id); - } - - cleanup: - js_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; - JSProperty *prop; - JSScope *scope; - JSScopeProperty *sprop; - uint32 slot; - - /* - * Handle old bug that took empty string as zero index. Also convert - * string indices to integers if appropriate. - */ - CHECK_FOR_STRING_INDEX(id); - - if (!js_LookupProperty(cx, obj, id, &obj2, &prop)) - return JS_FALSE; - if (!prop) { - jsval default_val; - -#if JS_BUG_NULL_INDEX_PROPS - /* Indexed properties defaulted to null in old versions. */ - default_val = (JSID_IS_INT(id) && JSID_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; - JSString *str; - - /* Kludge to allow (typeof foo == "undefined") tests. */ - JS_ASSERT(cx->fp->script); - pc = cx->fp->pc; - pc += js_CodeSpec[*pc].length; - if (Detecting(cx, pc)) - return JS_TRUE; - - /* Ok, bad undefined property reference: whine about it. */ - str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, - 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, prop); - return OBJ_GET_PROPERTY(cx, obj2, id, vp); - } - - /* Unlock obj2 before calling getter, relock after to avoid deadlock. */ - scope = OBJ_SCOPE(obj2); - sprop = (JSScopeProperty *) prop; - 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; - JSProperty *prop; - 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_STRING_INDEX(id); - - if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) - return JS_FALSE; - - if (prop && !OBJ_IS_NATIVE(pobj)) { - OBJ_DROP_PROPERTY(cx, pobj, prop); - prop = NULL; - } - sprop = (JSScopeProperty *) prop; - - /* - * 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) && JS_VERSION_IS_ECMA(cx)) - 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; - } - - /* - * Initialize the new property value (passed to setter) to undefined. - * Note that we store before calling addProperty, to match the order - * in js_DefineNativeProperty. - */ - if (SPROP_HAS_VALID_SLOT(sprop, scope)) - LOCKED_OBJ_SET_SLOT(obj, sprop->slot, JSVAL_VOID); - - /* XXXbe called with obj locked */ - ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, vp, - js_RemoveScopeProperty(cx, scope, id); - JS_UNLOCK_SCOPE(cx, scope); - return JS_FALSE); - - 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, 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 = JS_VERSION_IS_ECMA(cx) ? JSVAL_TRUE : JSVAL_VOID; - - /* - * Handle old bug that took empty string as zero index. Also convert - * string indices to integers if appropriate. - */ - CHECK_FOR_STRING_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 (JS_VERSION_IS_ECMA(cx)) { - *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) && JS_VERSION_IS_1_2(cx)) { - 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 (JS_VERSION_IS_1_2(cx) && 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_SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length) -{ - JSIdArray *rida; - - rida = (JSIdArray *) - JS_realloc(cx, ida, sizeof(JSIdArray) + (length-1) * sizeof(jsval)); - if (!rida) - JS_DestroyIdArray(cx, ida); - else - rida->length = length; - return rida; -} - -/* Private type used to iterate over all properties of a native JS object */ -struct JSNativeIteratorState { - jsint next_index; /* index into jsid array */ - JSIdArray *ida; /* all property ids in enumeration */ - JSNativeIteratorState *next; /* double-linked list support */ - JSNativeIteratorState **prevp; -}; - -/* - * 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) -{ - JSRuntime *rt; - JSObject *proto; - JSClass *clasp; - JSEnumerateOp enumerate; - JSScopeProperty *sprop, *lastProp; - jsint i, length; - JSScope *scope; - JSIdArray *ida; - JSNativeIteratorState *state; - - rt = cx->runtime; - 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)) - return JS_FALSE; - 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_GET_PROTO(cx, obj); - if (proto && scope == OBJ_SCOPE(proto)) { - ida = js_NewIdArray(cx, 0); - if (!ida) { - JS_UNLOCK_OBJ(cx, obj); - return JS_FALSE; - } - } else { - /* Object has a private scope; Enumerate all props in scope. */ - for (sprop = lastProp = SCOPE_LAST_PROP(scope); sprop; - sprop = sprop->parent) { - if (( -#ifdef DUMP_CALL_TABLE - (cx->options & JSOPTION_LOGCALL_TOSOURCE) || -#endif - (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); - return JS_FALSE; - } - i = length; - for (sprop = lastProp; sprop; sprop = sprop->parent) { - if (( -#ifdef DUMP_CALL_TABLE - (cx->options & JSOPTION_LOGCALL_TOSOURCE) || -#endif - (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); - return JS_FALSE; - } - state->ida = ida; - state->next_index = 0; - - JS_LOCK_RUNTIME(rt); - state->next = rt->nativeIteratorStates; - if (state->next) - state->next->prevp = &state->next; - state->prevp = &rt->nativeIteratorStates; - *state->prevp = state; - JS_UNLOCK_RUNTIME(rt); - - *statep = PRIVATE_TO_JSVAL(state); - if (idp) - *idp = INT_TO_JSVAL(length); - break; - - 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++]; - break; - } - /* FALL THROUGH */ - - case JSENUMERATE_DESTROY: - state = (JSNativeIteratorState *) JSVAL_TO_PRIVATE(*statep); - - JS_LOCK_RUNTIME(rt); - JS_ASSERT(rt->nativeIteratorStates); - JS_ASSERT(*state->prevp == state); - if (state->next) { - JS_ASSERT(state->next->prevp == &state->next); - state->next->prevp = state->prevp; - } - *state->prevp = state->next; - JS_UNLOCK_RUNTIME(rt); - - JS_DestroyIdArray(cx, state->ida); - JS_free(cx, state); - *statep = JSVAL_NULL; - break; - } - return JS_TRUE; -} - -void -js_MarkNativeIteratorStates(JSContext *cx) -{ - JSNativeIteratorState *state; - jsid *cursor, *end, id; - - state = cx->runtime->nativeIteratorStates; - if (!state) - return; - - do { - JS_ASSERT(*state->prevp == state); - cursor = state->ida->vector; - end = cursor + state->ida->length; - for (; cursor != end; ++cursor) { - id = *cursor; - if (JSID_IS_ATOM(id)) { - GC_MARK_ATOM(cx, JSID_TO_ATOM(id), NULL); - } else if (JSID_IS_OBJECT(id)) { - GC_MARK(cx, JSID_TO_OBJECT(id), "ida->vector[i]", NULL); - } - } - } while ((state = state->next) != NULL); -} - - -JSBool -js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, - jsval *vp, uintN *attrsp) -{ - JSBool writing; - JSObject *pobj; - JSProperty *prop; - JSClass *clasp; - JSScopeProperty *sprop; - JSCheckAccessOp check; - - writing = (mode & JSACC_WRITE) != 0; - switch (mode & JSACC_TYPEMASK) { - case JSACC_PROTO: - pobj = obj; - if (!writing) - *vp = OBJ_GET_SLOT(cx, obj, JSSLOT_PROTO); - *attrsp = JSPROP_PERMANENT; - break; - - case JSACC_PARENT: - JS_ASSERT(!writing); - pobj = obj; - *vp = OBJ_GET_SLOT(cx, obj, JSSLOT_PARENT); - *attrsp = JSPROP_READONLY | JSPROP_PERMANENT; - break; - - default: - if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) - return JS_FALSE; - if (!prop) { - if (!writing) - *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; - *attrsp = sprop->attrs; - if (!writing) { - *vp = (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))) - ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot) - : JSVAL_VOID; - } - OBJ_DROP_PROPERTY(cx, pobj, prop); - } - - /* - * If obj's class has a stub (null) checkAccess hook, use the per-runtime - * checkObjectAccess callback, if configured. - * - * We don't want to require all classes to supply a checkAccess hook; we - * need that hook only for certain classes used when precompiling scripts - * and functions ("brutal sharing"). But for general safety of built-in - * magic properties such as __proto__ and __parent__, we route all access - * checks, even for classes that stub out checkAccess, through the global - * checkObjectAccess hook. This covers precompilation-based sharing and - * (possibly unintended) runtime sharing across trust boundaries. - */ - clasp = OBJ_GET_CLASS(cx, pobj); - check = clasp->checkAccess; - if (!check) - check = cx->runtime->checkObjectAccess; - return !check || check(cx, pobj, ID_TO_VALUE(id), mode, vp); -} - -#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; - } -} - -#ifdef NARCISSUS -static JSBool -GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval) -{ - JSObject *tmp; - jsval xcval; - - while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL) - obj = tmp; - if (!OBJ_GET_PROPERTY(cx, obj, - ATOM_TO_JSID(cx->runtime->atomState - .ExecutionContextAtom), - &xcval)) { - return JS_FALSE; - } - if (JSVAL_IS_PRIMITIVE(xcval)) { - JS_ReportError(cx, "invalid ExecutionContext in global object"); - return JS_FALSE; - } - if (!OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(xcval), - ATOM_TO_JSID(cx->runtime->atomState.currentAtom), - rval)) { - return JS_FALSE; - } - return JS_TRUE; -} -#endif - -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) { -#ifdef NARCISSUS - JSObject *callee, *args; - jsval fval, nargv[3]; - JSBool ok; - - callee = JSVAL_TO_OBJECT(argv[-2]); - if (!OBJ_GET_PROPERTY(cx, callee, - ATOM_TO_JSID(cx->runtime->atomState.callAtom), - &fval)) { - return JS_FALSE; - } - if (JSVAL_IS_FUNCTION(cx, fval)) { - if (!GetCurrentExecutionContext(cx, obj, &nargv[2])) - return JS_FALSE; - args = js_GetArgsObject(cx, cx->fp); - if (!args) - return JS_FALSE; - nargv[0] = OBJECT_TO_JSVAL(obj); - nargv[1] = OBJECT_TO_JSVAL(args); - return js_InternalCall(cx, callee, fval, 3, nargv, rval); - } - if (JSVAL_IS_OBJECT(fval) && JSVAL_TO_OBJECT(fval) != callee) { - argv[-2] = fval; - ok = js_Call(cx, obj, argc, argv, rval); - argv[-2] = OBJECT_TO_JSVAL(callee); - return ok; - } -#endif - 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) { -#ifdef NARCISSUS - JSObject *callee, *args; - jsval cval, nargv[2]; - JSBool ok; - - callee = JSVAL_TO_OBJECT(argv[-2]); - if (!OBJ_GET_PROPERTY(cx, callee, - ATOM_TO_JSID(cx->runtime->atomState - .constructAtom), - &cval)) { - return JS_FALSE; - } - if (JSVAL_IS_FUNCTION(cx, cval)) { - if (!GetCurrentExecutionContext(cx, obj, &nargv[1])) - return JS_FALSE; - args = js_GetArgsObject(cx, cx->fp); - if (!args) - return JS_FALSE; - nargv[0] = OBJECT_TO_JSVAL(args); - return js_InternalCall(cx, callee, cval, 2, nargv, rval); - } - if (JSVAL_IS_OBJECT(cval) && JSVAL_TO_OBJECT(cval) != callee) { - argv[-2] = cval; - ok = js_Call(cx, obj, argc, argv, rval); - argv[-2] = OBJECT_TO_JSVAL(callee); - return ok; - } -#endif - 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; - JSString *str; - - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp->hasInstance) - return clasp->hasInstance(cx, obj, v, bp); -#ifdef NARCISSUS - { - jsval fval, rval; - - if (!OBJ_GET_PROPERTY(cx, obj, - ATOM_TO_JSID(cx->runtime->atomState - .hasInstanceAtom), - &fval)) { - return JS_FALSE; - } - if (JSVAL_IS_FUNCTION(cx, fval)) { - return js_InternalCall(cx, obj, fval, 1, &v, &rval) && - js_ValueToBoolean(cx, rval, bp); - } - } -#endif - str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, - OBJECT_TO_JSVAL(obj), NULL); - if (str) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_INSTANCEOF_RHS, - JS_GetStringBytes(str)); - } - return JS_FALSE; -} - -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 (!js_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, - ATOM_TO_JSID(cx->runtime->atomState - .classPrototypeAtom), - &v)) { - return JS_FALSE; - } - if (!JSVAL_IS_PRIMITIVE(v)) { - /* - * Set the newborn root in case v is otherwise unreferenced. - * It's ok to overwrite newborn roots here, since the getter - * called just above could have. Unlike the common GC rooting - * model, our callers do not have to protect protop thanks to - * this newborn root, since they all immediately create a new - * instance that delegates to this object, or just query the - * prototype for its class. - */ - cx->newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(v); - } - } - *protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL; - return JS_TRUE; -} - -/* - * For shared precompilation of function objects, we support cloning on entry - * to an execution context in which the function declaration or expression - * should be processed as if it were not precompiled, where the precompiled - * function's scope chain does not match the execution context's. The cloned - * function object carries its execution-context scope in its parent slot; it - * links to the precompiled function (the "clone-parent") via its proto slot. - * - * Note that this prototype-based delegation leaves an unchecked access path - * from the clone to the clone-parent's 'constructor' property. If the clone - * lives in a less privileged or shared scope than the clone-parent, this is - * a security hole, a sharing hazard, or both. Therefore we check all such - * accesses with the following getter/setter pair, which we use when defining - * 'constructor' in f.prototype for all function objects f. - */ -static JSBool -CheckCtorGetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSAtom *atom; - uintN attrs; - - atom = cx->runtime->atomState.constructorAtom; - JS_ASSERT(id == ATOM_KEY(atom)); - return OBJ_CHECK_ACCESS(cx, obj, ATOM_TO_JSID(atom), JSACC_READ, - vp, &attrs); -} - -static JSBool -CheckCtorSetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSAtom *atom; - uintN attrs; - - atom = cx->runtime->atomState.constructorAtom; - JS_ASSERT(id == ATOM_KEY(atom)); - return OBJ_CHECK_ACCESS(cx, obj, ATOM_TO_JSID(atom), JSACC_WRITE, - vp, &attrs); -} - -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 DontDelete prototype (which may be - * reset), while native or "system" constructors have DontEnum | ReadOnly | - * DontDelete. - */ - if (!OBJ_DEFINE_PROPERTY(cx, ctor, - ATOM_TO_JSID(cx->runtime->atomState - .classPrototypeAtom), - OBJECT_TO_JSVAL(proto), - JS_PropertyStub, JS_PropertyStub, - 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, - ATOM_TO_JSID(cx->runtime->atomState - .constructorAtom), - OBJECT_TO_JSVAL(ctor), - CheckCtorGetAccess, CheckCtorSetAccess, - 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; - jsid id; - jsval fval; - JSBool ok; - int stackDummy; - - if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); - return JS_FALSE; - } - - /* - * 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); - id = ATOM_TO_JSID(atom); - fval = JSVAL_VOID; -#if JS_HAS_XML_SUPPORT - if (OBJECT_IS_XML(cx, obj)) { - JSXMLObjectOps *ops; - - ops = (JSXMLObjectOps *) obj->map->ops; - obj = ops->getMethod(cx, obj, id, &fval); - ok = (obj != NULL); - } else -#endif - { - ok = OBJ_GET_PROPERTY(cx, obj, id, &fval); - } - if (!ok) - JS_ClearPendingException(cx); - ok = JSVAL_IS_PRIMITIVE(fval) || - js_InternalCall(cx, obj, fval, argc, argv, rval); - 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 = GetClassPrototype(cx, NULL, 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 -#include - -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 (JSID_IS_ATOM(sprop->id)) - GC_MARK_ATOM(cx, JSID_TO_ATOM(sprop->id), arg); - else if (JSID_IS_OBJECT(sprop->id)) - GC_MARK(cx, JSID_TO_OBJECT(sprop->id), "id", arg); - -#if JS_HAS_GETTER_SETTER - if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) { -#ifdef GC_MARK_DEBUG - char buf[64]; - JSAtom *atom = JSID_TO_ATOM(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(scope->map.freeslot, scope->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; -} - -JSBool -js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v) -{ - JSScope *scope; - uint32 nslots; - JSClass *clasp; - jsval *newslots; - - JS_LOCK_OBJ(cx, obj); - scope = OBJ_SCOPE(obj); - nslots = (uint32) obj->slots[-1]; - if (slot >= nslots) { - /* - * At this point, obj may or may not own scope. If some path calls - * js_GetMutableScope but does not add a slot-owning property, then - * scope->object == obj but nslots will be nominal. If obj shares a - * prototype's scope, then we cannot update scope->map here, but we - * must update obj->slots[-1] when we grow obj->slots. - * - * See js_Mark, before the last return, where we make a special case - * for unmutated (scope->object != obj) objects. - */ - JS_ASSERT(nslots == JS_INITIAL_NSLOTS); - clasp = LOCKED_OBJ_GET_CLASS(obj); - nslots = JSSLOT_FREE(clasp); - if (clasp->reserveSlots) - nslots += clasp->reserveSlots(cx, obj); - JS_ASSERT(slot < nslots); - - newslots = AllocSlots(cx, obj->slots, nslots); - if (!newslots) { - JS_UNLOCK_SCOPE(cx, scope); - return JS_FALSE; - } - if (scope->object == obj) - scope->map.nslots = nslots; - obj->slots = newslots; - } - - /* Whether or not we grew nslots, we may need to advance freeslot. */ - if (scope->object == obj && slot >= scope->map.freeslot) - scope->map.freeslot = slot + 1; - - obj->slots[slot] = v; - JS_UNLOCK_SCOPE(cx, scope); - return JS_TRUE; -} - -#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 deleted file mode 100644 index a2400e982..000000000 --- a/src/dom/js/jsobj.h +++ /dev/null @@ -1,527 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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. */ -#define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp) \ - (obj)->map->ops->lookupProperty(cx,obj,id,objp,propp) -#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) \ - : JS_TRUE) - -#define OBJ_TO_INNER_OBJECT(cx,obj) \ - JS_BEGIN_MACRO \ - JSClass *clasp_ = OBJ_GET_CLASS(cx, obj); \ - if (clasp_->flags & JSCLASS_IS_EXTENDED) { \ - JSExtendedClass *xclasp_ = (JSExtendedClass*)clasp_; \ - if (xclasp_->innerObject) \ - obj = xclasp_->innerObject(cx, obj); \ - } \ - JS_END_MACRO - -/* - * 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; - -extern JSObject * -js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth); - -/* - * A With object is like a Block object, in that both have one reserved slot - * telling the stack depth of the relevant slots (the slot whose value is the - * object named in the with statement, the slots containing the block's local - * variables); and both have a private slot referring to the JSStackFrame in - * whose activation they were created (or null if the with or block object - * outlives the frame). - */ -#define JSSLOT_BLOCK_DEPTH (JSSLOT_PRIVATE + 1) - -#define OBJ_BLOCK_DEPTH(cx,obj) \ - JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_BLOCK_DEPTH)) -#define OBJ_SET_BLOCK_DEPTH(cx,obj,depth) \ - OBJ_SET_SLOT(cx, obj, JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)) - -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) (JS_PTR_TO_UINT32((he)->value) & SHARP_BIT) -#define MAKE_SHARP(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)|SHARP_BIT)) -#define IS_BUSY(he) (JS_PTR_TO_UINT32((he)->value) & BUSY_BIT) -#define MAKE_BUSY(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)|BUSY_BIT)) -#define CLEAR_BUSY(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)&~BUSY_BIT)) - -extern JSHashEntry * -js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, - jschar **sp); - -extern void -js_LeaveSharpObject(JSContext *cx, JSIdArray **idap); - -/* - * Mark objects stored in map if GC happens between js_EnterSharpObject - * and js_LeaveSharpObject. GC calls this when map->depth > 0. - */ -extern void -js_GCMarkSharpMap(JSContext *cx, JSSharpObjectMap *map); - -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 JSBool -js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, - 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 JSBool -js_FindConstructor(JSContext *cx, JSObject *start, const char *name, jsval *vp); - -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); - -/* - * Native property add and lookup variants that hide id in the hidden atom - * subspace, so as to avoid collisions between internal properties such as - * formal arguments and local variables in function objects, and externally - * set properties with the same ids. - */ -extern JSScopeProperty * -js_AddHiddenProperty(JSContext *cx, JSObject *obj, jsid id, - JSPropertyOp getter, JSPropertyOp setter, uint32 slot, - uintN attrs, uintN flags, intN shortid); - -extern JSBool -js_LookupHiddenProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, - JSProperty **propp); - -/* - * 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). - */ -extern JS_FRIEND_API(JSBool) -js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, - JSProperty **propp); - -/* - * Specialized subroutine that allows caller to preset JSRESOLVE_* flags. - */ -extern JSBool -js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, - JSObject **objp, JSProperty **propp); - -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); - -/* - * Unlike realloc(3), this function frees ida on failure. - */ -extern JSIdArray * -js_SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length); - -extern JSBool -js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp); - -extern void -js_MarkNativeIteratorStates(JSContext *cx); - -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 JSBool -js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v); - -extern JSObject * -js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller); - -extern JSBool -js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj, - JSPrincipals *principals, const char *caller); -JS_END_EXTERN_C - -#endif /* jsobj_h___ */ diff --git a/src/dom/js/jsopcode.c b/src/dom/js/jsopcode.c deleted file mode 100644 index 80c7eb4dd..000000000 --- a/src/dom/js/jsopcode.c +++ /dev/null @@ -1,3167 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set sw=4 ts=8 et tw=80: - * - * ***** 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 -#endif -#include -#include -#include -#include -#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 "jsregexp.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_default_str[] = "default"; - -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(JSBool) -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 JS_FALSE; - pc += len; - } - return JS_TRUE; -} - -JS_FRIEND_API(uintN) -js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, - JSBool lines, FILE *fp) -{ - JSOp op; - const JSCodeSpec *cs; - ptrdiff_t len, off, jmplen; - uint32 type; - JSAtom *atom; - JSString *str; - - 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 = (ptrdiff_t) cs->length; - fprintf(fp, "%05u:", loc); - if (lines) - fprintf(fp, "%4u", JS_PCToLineNumber(cx, script, pc)); - fprintf(fp, " %s", cs->name); - type = cs->format & JOF_TYPEMASK; - switch (type) { - case JOF_BYTE: - if (op == JSOP_TRAP) { - op = JS_GetTrapOpcode(cx, script, pc); - if (op == JSOP_LIMIT) - return 0; - len = (ptrdiff_t) 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; - fprintf(fp, " %s", JS_GetStringBytes(str)); - break; - - case JOF_UINT16: - fprintf(fp, " %u", GET_ARGC(pc)); - break; - -#if JS_HAS_SWITCH_STATEMENT - case JOF_TABLESWITCH: - case JOF_TABLESWITCHX: - { - jsbytecode *pc2; - jsint i, low, high; - - jmplen = (type == JOF_TABLESWITCH) ? JUMP_OFFSET_LEN - : JUMPX_OFFSET_LEN; - pc2 = pc; - off = GetJumpOffset(pc, pc2); - pc2 += jmplen; - low = GET_JUMP_OFFSET(pc2); - pc2 += JUMP_OFFSET_LEN; - high = GET_JUMP_OFFSET(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 += jmplen; - } - len = 1 + pc2 - pc; - break; - } - - case JOF_LOOKUPSWITCH: - case JOF_LOOKUPSWITCHX: - { - jsbytecode *pc2; - jsatomid npairs; - - jmplen = (type == JOF_LOOKUPSWITCH) ? JUMP_OFFSET_LEN - : JUMPX_OFFSET_LEN; - pc2 = pc; - off = GetJumpOffset(pc, pc2); - pc2 += jmplen; - npairs = 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 += jmplen; - - str = js_ValueToSource(cx, ATOM_KEY(atom)); - if (!str) - return 0; - fprintf(fp, "\n\t%s: %d", JS_GetStringBytes(str), off); - 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_INDEXCONST: - 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; - fprintf(fp, " %s", JS_GetStringBytes(str)); - break; -#endif - - case JOF_UINT24: - if (op == JSOP_FINDNAME) { - /* Special case to avoid a JOF_FINDNAME just for this op. */ - atom = js_GetAtom(cx, &script->atomMap, GET_LITERAL_INDEX(pc)); - str = js_ValueToSource(cx, ATOM_KEY(atom)); - if (!str) - return 0; - fprintf(fp, " %s", JS_GetStringBytes(str)); - break; - } - - JS_ASSERT(op == JSOP_UINT24 || op == JSOP_LITERAL); - fprintf(fp, " %u", GET_LITERAL_INDEX(pc)); - break; - - case JOF_LITOPX: - atom = js_GetAtom(cx, &script->atomMap, GET_LITERAL_INDEX(pc)); - str = js_ValueToSource(cx, ATOM_KEY(atom)); - if (!str) - return 0; - - /* - * Bytecode: JSOP_LITOPX op [ if JSOP_DEFLOCALFUN]. - * Advance pc to point at op. - */ - pc += 1 + LITERAL_INDEX_LEN; - op = *pc; - cs = &js_CodeSpec[op]; - fprintf(fp, " %s op %s", JS_GetStringBytes(str), cs->name); -#if JS_HAS_LEXICAL_CLOSURE - if ((cs->format & JOF_TYPEMASK) == JOF_INDEXCONST) - fprintf(fp, " %u", GET_VARNO(pc)); -#endif - - /* - * Set len to advance pc to skip op and any other immediates (namely, - * if JSOP_DEFLOCALFUN). - */ - JS_ASSERT(cs->length > ATOM_INDEX_LEN); - len = cs->length - ATOM_INDEX_LEN; - break; - - 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 { -#ifdef JS_C_STRINGS_ARE_UTF8 - /* If this is a surrogate pair, make sure to print the pair. */ - if (c >= 0xD800 && c <= 0xDBFF) { - jschar buffer[3]; - buffer[0] = c; - buffer[1] = *++t; - buffer[2] = 0; - if (t == z) { - char numbuf[10]; - JS_snprintf(numbuf, sizeof numbuf, "0x%x", c); - JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, - js_GetErrorMessage, NULL, - JSMSG_BAD_SURROGATE_CHAR, - numbuf); - ok = JS_FALSE; - break; - } - ok = Sprint(sp, "%hs", buffer) >= 0; - } else { - /* Print as UTF-8 string. */ - ok = Sprint(sp, "%hc", c) >= 0; - } -#else - /* Use \uXXXX or \xXX if the string can't be displayed as UTF-8. */ - ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0; -#endif - } - if (!ok) - return NULL; - } - - /* Sprint the closing quote and return the quoted string. */ - if (quote && Sprint(sp, "%c", (char)quote) < 0) - return NULL; - - /* - * If we haven't Sprint'd anything yet, Sprint an empty string so that - * the OFF2STR below gives a valid result. - */ - if (off == sp->offset && Sprint(sp, "") < 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 */ - JSPackedBool pretty; /* pretty-print: indent, use newlines */ - JSPackedBool grouped; /* in parenthesized expression context */ - JSScript *script; /* script being printed */ - JSScope *scope; /* script function scope */ -}; - -/* - * Hack another flag, a la JS_DONT_PRETTY_PRINT, into uintN indent parameters - * to functions such as js_DecompileFunction and js_NewPrinter. This time, as - * opposed to JS_DONT_PRETTY_PRINT back in the dark ages, we can assume that a - * uintN is at least 32 bits. - */ -#define JS_IN_GROUP_CONTEXT 0x10000 - -JSPrinter * -js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty) -{ - JSPrinter *jp; - - 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 & ~JS_IN_GROUP_CONTEXT; - jp->pretty = pretty; - jp->grouped = (indent & JS_IN_GROUP_CONTEXT) != 0; - jp->script = NULL; - jp->scope = NULL; - 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; - JSAtom *label; - jsint order; /* source order for stable tableswitch sort */ -} TableEntry; - -static int -CompareOffsets(const void *v1, const void *v2, void *arg) -{ - const TableEntry *te1 = (const TableEntry *) v1, - *te2 = (const TableEntry *) v2; - - if (te1->offset == te2->offset) - return (int) (te1->order - te2->order); - return (int) (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, "\t%s:\n", js_default_str); - 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; - off2 = (i + 1 < tableLength) ? table[i + 1].offset : 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. But if table[i].label - * is non-null, key was constant-propagated and label is the - * name of the const we should show as the case label. We set - * key to undefined so this identifier is escaped, if required - * by non-ASCII characters, but not quoted, by QuoteString. - */ - if (table[i].label) { - str = ATOM_TO_STRING(table[i].label); - key = JSVAL_VOID; - } else { - str = js_ValueToString(cx, key); - if (!str) - return JS_FALSE; - } - rval = QuoteString(&ss->sprinter, str, - (jschar)(JSVAL_IS_STRING(key) ? '"' : 0)); - if (!rval) - return JS_FALSE; - RETRACT(&ss->sprinter, rval); - jp->indent += 2; - 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, "\t%s:\n", js_default_str); - 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, "\t%s:;\n", js_default_str); - 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(JSID_IS_ATOM(sprop->id)); - if ((uintN) sprop->shortid == slot) - return JSID_TO_ATOM(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) -{ - if (sn) { - if (SN_TYPE(sn) == SRC_VAR) - return "var "; - if (SN_TYPE(sn) == SRC_CONST) - return "const "; - } - return ""; -} - -static JSBool -Decompile(SprintStack *ss, jsbytecode *pc, intN nb) -{ - JSContext *cx; - JSPrinter *jp, *jp2; - jsbytecode *endpc, *done, *forelem_tail, *forelem_done; - ptrdiff_t tail, todo, len, oplen, cond, next; - JSOp op, lastop, saveop; - const JSCodeSpec *cs, *topcs; - jssrcnote *sn, *sn2; - const char *lval, *rval, *xval, *fmt; - jsint i, argc; - char **argv; - jsatomid atomIndex; - JSAtom *atom; - JSObject *obj; - JSFunction *fun; - JSString *str; - JSBool ok; -#if JS_HAS_XML_SUPPORT - JSBool foreach, inXML, quoteAttr; -#else -#define inXML JS_FALSE -#endif - jsval val; - int stackDummy; - static const char catch_cookie[] = "/*CATCH*/"; - static const char with_cookie[] = "/*WITH*/"; - -/* - * 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 - -/* - * Callers know that ATOM_IS_STRING(atom), and we leave it to the optimizer to - * common ATOM_TO_STRING(atom) here and near the call sites. - */ -#define ATOM_IS_IDENTIFIER(atom) \ - (!ATOM_KEYWORD(atom) && js_IsIdentifier(ATOM_TO_STRING(atom))) - -/* - * Given an atom already fetched from jp->script's atom map, quote/escape its - * string appropriately into rval, and select fmt from the quoted and unquoted - * alternatives. - */ -#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \ - JS_BEGIN_MACRO \ - jschar quote_; \ - if (!ATOM_IS_IDENTIFIER(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 - -/* - * Get atom from jp->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 \ - atom = GET_ATOM(cx, jp->script, pc); \ - GET_QUOTE_AND_FMT(qfmt, ufmt, rval); \ - JS_END_MACRO - - cx = ss->sprinter.context; - if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); - return JS_FALSE; - } - - jp = ss->printer; - endpc = pc + nb; - forelem_tail = forelem_done = NULL; - tail = -1; - todo = -2; /* NB: different from Sprint() error return. */ - op = JSOP_NOP; - sn = NULL; - rval = NULL; -#if JS_HAS_XML_SUPPORT - foreach = inXML = quoteAttr = JS_FALSE; -#endif - - 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 if (!inXML) { - todo = Sprint(&ss->sprinter, "%s %s %s", - lval, cs->token, rval); - } else { - /* In XML, just concatenate the two operands. */ - JS_ASSERT(op == JSOP_ADD); - todo = Sprint(&ss->sprinter, "%s%s", lval, rval); - } - break; - - case 1: - rval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s%s", cs->token, rval); - break; - - case 0: - todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token)); - break; - - default: - todo = -2; - break; - } - } else { - switch (op) { -#define BEGIN_LITOPX_CASE(OP) \ - case OP: \ - atomIndex = GET_ATOM_INDEX(pc); \ - do_##OP: \ - atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); - -#define END_LITOPX_CASE \ - break; - - 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_printf(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; - if (*pc == JSOP_LITOPX) { - atomIndex = GET_LITERAL_INDEX(pc); - pc += 1 + LITERAL_INDEX_LEN; - LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); - ++pc; - } else { - LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); - atomIndex = GET_ATOM_INDEX(pc); - pc += js_CodeSpec[JSOP_INITCATCHVAR].length; - } - atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); - rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); - if (!rval) - return JS_FALSE; - RETRACT(&ss->sprinter, rval); - js_printf(jp, "%s", rval); - 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; - todo = Sprint(&ss->sprinter, catch_cookie); - 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; - js_puts(jp2, "\n"); - ok = js_DecompileFunction(jp2, fun); - if (ok) { - js_puts(jp2, "\n"); - str = js_GetPrinterOutput(jp2); - if (str) - js_printf(jp, "%s\n", JS_GetStringBytes(str)); - else - ok = JS_FALSE; - } - js_DestroyPrinter(jp2); - if (!ok) - return JS_FALSE; - - 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: - do_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 exception_cookie[] = "/*EXCEPTION*/"; - static const char retsub_pc_cookie[] = "/*RETSUB_PC*/"; - - 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, exception_cookie); - if (todo < 0 || !PushOff(ss, todo, op)) - return JS_FALSE; - todo = Sprint(&ss->sprinter, retsub_pc_cookie); - break; - - case JSOP_RETSUB: - rval = POP_STR(); - LOCAL_ASSERT(strcmp(rval, retsub_pc_cookie) == 0); - lval = POP_STR(); - LOCAL_ASSERT(strcmp(lval, exception_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. - */ - LOCAL_ASSERT(ss->top >= (uintN) GET_ATOM_INDEX(pc)); - 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; - - case JSOP_ENTERWITH: - JS_ASSERT(!js_GetSrcNote(jp->script, pc)); - 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(); - if (sn && SN_TYPE(sn) == SRC_CATCH) { - LOCAL_ASSERT(strcmp(rval, catch_cookie) == 0); - LOCAL_ASSERT((uintN) js_GetSrcNoteOffset(sn, 0) == ss->top); - break; - } - LOCAL_ASSERT(strcmp(rval, with_cookie) == 0); - jp->indent -= 4; - js_printf(jp, "\t}\n"); - break; - - case JSOP_SETRVAL: - case JSOP_RETURN: - lval = js_CodeSpec[JSOP_RETURN].name; - rval = POP_STR(); - if (*rval != '\0') - js_printf(jp, "\t%s %s;\n", lval, rval); - else - js_printf(jp, "\t%s;\n", lval); - todo = -2; - break; - -#if JS_HAS_EXCEPTIONS - case JSOP_THROWING: - todo = -2; - break; - - 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_IS_IDENTIFIER(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: -#if JS_HAS_XML_SUPPORT - if (foreach) { - foreach = JS_FALSE; - js_printf(jp, "\tfor %s (%s%s", - js_each_str, VarPrefix(sn), lval); - } else -#endif - 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 && *xval) { - js_printf(jp, - (js_CodeSpec[lastop].format & JOF_XMLNAME) - ? ".%s" - : "[%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; - -#if JS_HAS_GETTER_SETTER - case JSOP_GETTER: - case JSOP_SETTER: - todo = -2; - break; -#endif - - 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: - case JSOP_SETGVAR: - atomIndex = GET_ATOM_INDEX(pc); - - do_JSOP_SETCONST: - atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); - - 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, - (js_CodeSpec[lastop].format & JOF_XMLNAME) - ? "%s %s.%s" - : "%s %s[%s]", - js_delete_str, lval, xval); - break; - -#if JS_HAS_XML_SUPPORT - case JSOP_DELDESC: - xval = POP_STR(); - lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s %s..%s", - js_delete_str, lval, xval); - break; -#endif - - 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: - case JSOP_INCGVAR: - case JSOP_DECGVAR: - 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(); - if (*xval != '\0') { - todo = Sprint(&ss->sprinter, - (js_CodeSpec[lastop].format & JOF_XMLNAME) - ? "%s%s.%s" - : "%s%s[%s]", - js_incop_str[!(cs->format & JOF_INC)], - lval, xval); - } else { - todo = Sprint(&ss->sprinter, "%s%s", - js_incop_str[!(cs->format & JOF_INC)], lval); - } - 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: - case JSOP_GVARINC: - case JSOP_GVARDEC: - 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(); - if (*xval != '\0') { - todo = Sprint(&ss->sprinter, - (js_CodeSpec[lastop].format & JOF_XMLNAME) - ? "%s.%s%s" - : "%s[%s]%s", - lval, xval, - js_incop_str[!(cs->format & JOF_INC)]); - } else { - todo = Sprint(&ss->sprinter, "%s%s", - lval, js_incop_str[!(cs->format & JOF_INC)]); - } - break; - - case JSOP_GETPROP2: - op = JSOP_GETPROP; - (void) PopOff(ss, lastop); - /* FALL THROUGH */ - - case JSOP_GETPROP: - atom = GET_ATOM(cx, jp->script, pc); - - do_getprop: - GET_QUOTE_AND_FMT("%s[%s]", "%s.%s", rval); - - do_getprop_lval: - lval = POP_STR(); - todo = Sprint(&ss->sprinter, fmt, lval, rval); - break; - -#if JS_HAS_XML_SUPPORT - BEGIN_LITOPX_CASE(JSOP_GETMETHOD) - sn = js_GetSrcNote(jp->script, pc); - if (sn && SN_TYPE(sn) == SRC_PCBASE) - goto do_getprop; - GET_QUOTE_AND_FMT("%s.function::[%s]", "%s.function::%s", rval); - goto do_getprop_lval; - - BEGIN_LITOPX_CASE(JSOP_SETMETHOD) - sn = js_GetSrcNote(jp->script, pc); - if (sn && SN_TYPE(sn) == SRC_PCBASE) - goto do_setprop; - GET_QUOTE_AND_FMT("%s.function::[%s] %s= %s", - "%s.function::%s %s= %s", - xval); - goto do_setprop_rval; -#endif - - case JSOP_SETPROP: - atom = GET_ATOM(cx, jp->script, pc); - - do_setprop: - GET_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval); - - do_setprop_rval: - 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, - (js_CodeSpec[lastop].format & JOF_XMLNAME) - ? "%s.%s" - : "%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, - (js_CodeSpec[lastop].format & JOF_XMLNAME) - ? "%s.%s %s= %s" - : "%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: - case JSOP_GETGVAR: - 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); - goto do_sprint_int; - - case JSOP_UINT24: - i = (jsint) GET_LITERAL_INDEX(pc); - do_sprint_int: - todo = Sprint(&ss->sprinter, "%u", (unsigned) i); - break; - - case JSOP_LITERAL: - atomIndex = GET_LITERAL_INDEX(pc); - goto do_JSOP_STRING; - - case JSOP_FINDNAME: - atomIndex = GET_LITERAL_INDEX(pc); - todo = Sprint(&ss->sprinter, ""); - if (todo < 0 || !PushOff(ss, todo, op)) - return JS_FALSE; - atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); - goto do_name; - - case JSOP_LITOPX: - atomIndex = GET_LITERAL_INDEX(pc); - op = pc[1 + LITERAL_INDEX_LEN]; - switch (op) { - case JSOP_ANONFUNOBJ: goto do_JSOP_ANONFUNOBJ; - case JSOP_BINDNAME: goto do_JSOP_BINDNAME; - case JSOP_CLOSURE: goto do_JSOP_CLOSURE; -#if JS_HAS_EXPORT_IMPORT - case JSOP_EXPORTNAME: goto do_JSOP_EXPORTNAME; -#endif -#if JS_HAS_XML_SUPPORT - case JSOP_GETMETHOD: goto do_JSOP_GETMETHOD; - case JSOP_SETMETHOD: goto do_JSOP_SETMETHOD; -#endif - case JSOP_NAMEDFUNOBJ: goto do_JSOP_NAMEDFUNOBJ; - case JSOP_NUMBER: goto do_JSOP_NUMBER; - case JSOP_OBJECT: goto do_JSOP_OBJECT; -#if JS_HAS_XML_SUPPORT - case JSOP_QNAMECONST: goto do_JSOP_QNAMECONST; - case JSOP_QNAMEPART: goto do_JSOP_QNAMEPART; -#endif - case JSOP_REGEXP: goto do_JSOP_REGEXP; - case JSOP_SETCONST: goto do_JSOP_SETCONST; - case JSOP_STRING: goto do_JSOP_STRING; -#if JS_HAS_XML_SUPPORT - case JSOP_XMLCDATA: goto do_JSOP_XMLCDATA; - case JSOP_XMLCOMMENT: goto do_JSOP_XMLCOMMENT; - case JSOP_XMLOBJECT: goto do_JSOP_XMLOBJECT; - case JSOP_XMLPI: goto do_JSOP_XMLPI; -#endif - default: JS_ASSERT(0); - } - /* NOTREACHED */ - break; - - BEGIN_LITOPX_CASE(JSOP_NUMBER) - 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); - } - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_STRING) - rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), - inXML ? 0 : (jschar)'"'); - if (!rval) - return JS_FALSE; - todo = STR2OFF(&ss->sprinter, rval); - END_LITOPX_CASE - - case JSOP_OBJECT: - case JSOP_REGEXP: - case JSOP_ANONFUNOBJ: - case JSOP_NAMEDFUNOBJ: - atomIndex = GET_ATOM_INDEX(pc); - - do_JSOP_OBJECT: - do_JSOP_REGEXP: - do_JSOP_ANONFUNOBJ: - do_JSOP_NAMEDFUNOBJ: - atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); - if (op == JSOP_OBJECT || op == JSOP_REGEXP) { - if (!js_regexp_toString(cx, ATOM_TO_OBJECT(atom), 0, NULL, - &val)) { - return JS_FALSE; - } - } else { - if (!js_fun_toString(cx, ATOM_TO_OBJECT(atom), - (pc + len < endpc && - pc[len] == JSOP_GROUP) - ? JS_IN_GROUP_CONTEXT | - JS_DONT_PRETTY_PRINT - : 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 jmplen, off, off2; - jsint j, n, low, high; - TableEntry *table, pivot; - - sn = js_GetSrcNote(jp->script, pc); - JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); - len = js_GetSrcNoteOffset(sn, 0); - jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN - : JUMPX_OFFSET_LEN; - pc2 = pc; - off = GetJumpOffset(pc, pc2); - pc2 += jmplen; - low = GET_JUMP_OFFSET(pc2); - pc2 += JUMP_OFFSET_LEN; - high = GET_JUMP_OFFSET(pc2); - pc2 += JUMP_OFFSET_LEN; - - 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++) { - table[j].label = NULL; - off2 = GetJumpOffset(pc, pc2); - if (off2) { - sn = js_GetSrcNote(jp->script, pc2); - if (sn) { - JS_ASSERT(SN_TYPE(sn) == SRC_LABEL); - table[j].label = - js_GetAtom(cx, &jp->script->atomMap, - (jsatomid) - js_GetSrcNoteOffset(sn, 0)); - } - table[j].key = INT_TO_JSVAL(low + i); - table[j].offset = off2; - table[j].order = j; - j++; - } - pc2 += jmplen; - } - js_HeapSort(table, (size_t) j, &pivot, sizeof(TableEntry), - 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 jmplen, off, off2; - jsatomid npairs, k; - TableEntry *table; - - sn = js_GetSrcNote(jp->script, pc); - JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); - len = js_GetSrcNoteOffset(sn, 0); - jmplen = (op == JSOP_LOOKUPSWITCH) ? JUMP_OFFSET_LEN - : JUMPX_OFFSET_LEN; - pc2 = pc; - off = GetJumpOffset(pc, pc2); - pc2 += jmplen; - npairs = GET_ATOM_INDEX(pc2); - pc2 += ATOM_INDEX_LEN; - - table = (TableEntry *) - JS_malloc(cx, (size_t)npairs * sizeof *table); - if (!table) - return JS_FALSE; - for (k = 0; k < npairs; k++) { - sn = js_GetSrcNote(jp->script, pc2); - if (sn) { - JS_ASSERT(SN_TYPE(sn) == SRC_LABEL); - table[k].label = - js_GetAtom(cx, &jp->script->atomMap, (jsatomid) - js_GetSrcNoteOffset(sn, 0)); - } else { - table[k].label = NULL; - } - atom = GET_ATOM(cx, jp->script, pc2); - pc2 += ATOM_INDEX_LEN; - off2 = GetJumpOffset(pc, pc2); - pc2 += jmplen; - table[k].key = ATOM_KEY(atom); - table[k].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 - JS_VERSION_IS_ECMA(cx) ? "==" : -#endif - "=", - rval); - break; -#endif - -#if JS_HAS_LEXICAL_CLOSURE - BEGIN_LITOPX_CASE(JSOP_CLOSURE) - JS_ASSERT(ATOM_IS_OBJECT(atom)); - todo = -2; - goto do_function; - END_LITOPX_CASE -#endif - -#if JS_HAS_EXPORT_IMPORT - case JSOP_EXPORTALL: - js_printf(jp, "\texport *\n"); - todo = -2; - break; - - BEGIN_LITOPX_CASE(JSOP_EXPORTNAME) - 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; - END_LITOPX_CASE - - case JSOP_IMPORTALL: - lval = POP_STR(); - js_printf(jp, "\timport %s.*\n", lval); - todo = -2; - break; - - case JSOP_IMPORTPROP: - do_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; - if (js_CodeSpec[lastop].format & JOF_XMLNAME) - goto do_importprop; - 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: - atom = GET_ATOM(cx, jp->script, pc); - xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), - (jschar) - (ATOM_IS_IDENTIFIER(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) { - rval += strlen(js_function_str) + 1; - todo = Sprint(&ss->sprinter, "%s%s%s %s%.*s", - lval, - (lval[1] != '\0') ? ", " : "", - (lastop == JSOP_GETTER) - ? js_get_str : js_set_str, - xval, - strlen(rval) - 1, - rval); - } 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 */ - -#if JS_HAS_XML_SUPPORT - case JSOP_STARTXML: - case JSOP_STARTXMLEXPR: - inXML = op == JSOP_STARTXML; - todo = -2; - break; - - case JSOP_DEFXMLNS: - rval = POP_STR(); - js_printf(jp, "\t%s %s %s = %s;\n", - js_default_str, js_xml_str, js_namespace_str, rval); - todo = -2; - break; - - case JSOP_ANYNAME: - todo = SprintPut(&ss->sprinter, "*", 1); - break; - - BEGIN_LITOPX_CASE(JSOP_QNAMEPART) - goto do_name; - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_QNAMECONST) - rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); - if (!rval) - return JS_FALSE; - RETRACT(&ss->sprinter, rval); - lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s::%s", lval, rval); - END_LITOPX_CASE - - case JSOP_QNAME: - rval = POP_STR(); - lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s::[%s]", lval, rval); - break; - - case JSOP_TOATTRNAME: - rval = POP_STR(); - todo = Sprint(&ss->sprinter, "@%s", rval); - break; - - case JSOP_TOATTRVAL: - todo = -2; - break; - - case JSOP_ADDATTRNAME: - rval = POP_STR(); - lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s %s", lval, rval); - /* This gets reset by all XML tag expressions. */ - quoteAttr = JS_TRUE; - break; - - case JSOP_ADDATTRVAL: - rval = POP_STR(); - lval = POP_STR(); - if (quoteAttr) - todo = Sprint(&ss->sprinter, "%s=\"%s\"", lval, rval); - else - todo = Sprint(&ss->sprinter, "%s=%s", lval, rval); - break; - - case JSOP_BINDXMLNAME: - /* Leave the name stacked and push a dummy string. */ - todo = Sprint(&ss->sprinter, ""); - break; - - case JSOP_SETXMLNAME: - /* Pop the r.h.s., the dummy string, and the name. */ - rval = POP_STR(); - (void) PopOff(ss, op); - lval = POP_STR(); - goto do_setlval; - - case JSOP_XMLELTEXPR: - case JSOP_XMLTAGEXPR: - todo = Sprint(&ss->sprinter, "{%s}", POP_STR()); - inXML = JS_TRUE; - /* If we're an attribute value, we shouldn't quote this. */ - quoteAttr = JS_FALSE; - break; - - case JSOP_TOXMLLIST: - todo = Sprint(&ss->sprinter, "<>%s", POP_STR()); - inXML = JS_FALSE; - break; - - case JSOP_FOREACH: - foreach = JS_TRUE; - todo = -2; - break; - - case JSOP_TOXML: - inXML = JS_FALSE; - /* FALL THROUGH */ - - case JSOP_XMLNAME: - case JSOP_FILTER: - /* Conversion and prefix ops do nothing in the decompiler. */ - todo = -2; - break; - - case JSOP_ENDFILTER: - rval = POP_STR(); - lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval); - break; - - case JSOP_DESCENDANTS: - rval = POP_STR(); - lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s..%s", lval, rval); - break; - - BEGIN_LITOPX_CASE(JSOP_XMLOBJECT) - atom = GET_ATOM(cx, jp->script, pc); - todo = Sprint(&ss->sprinter, "", - ATOM_TO_OBJECT(atom)); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_XMLCDATA) - todo = SprintPut(&ss->sprinter, "sprinter, ATOM_TO_STRING(atom), 0)) - return JS_FALSE; - SprintPut(&ss->sprinter, "]]>", 3); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_XMLCOMMENT) - todo = SprintPut(&ss->sprinter, "", 3); - END_LITOPX_CASE - - BEGIN_LITOPX_CASE(JSOP_XMLPI) - rval = JS_strdup(cx, POP_STR()); - if (!rval) - return JS_FALSE; - todo = SprintPut(&ss->sprinter, "sprinter, ATOM_TO_STRING(atom), 0) && - SprintPut(&ss->sprinter, " ", 1) >= 0 && - SprintPut(&ss->sprinter, rval, strlen(rval)); - JS_free(cx, (char *)rval); - if (!ok) - return JS_FALSE; - SprintPut(&ss->sprinter, "?>", 2); - END_LITOPX_CASE - - case JSOP_GETFUNNS: - todo = SprintPut(&ss->sprinter, js_function_str, 8); - break; -#endif /* JS_HAS_XML_SUPPORT */ - - default: - todo = -2; - break; - -#undef BEGIN_LITOPX_CASE -#undef END_LITOPX_CASE - } - } - - 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 inXML -#undef DECOMPILE_CODE -#undef POP_STR -#undef LOCAL_ASSERT -#undef ATOM_IS_IDENTIFIER -#undef GET_QUOTE_AND_FMT -#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; - - if (!fun->interpreted) { - js_printf(jp, native_code_str); - return JS_TRUE; - } - script = fun->u.script; - 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_printf(jp, "\t"); - } else { - if (!jp->grouped && (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->interpreted && fun->object) { - size_t paramsize; - - /* - * 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); - paramsize = nargs * sizeof(JSAtom *); - JS_ARENA_ALLOCATE_CAST(params, JSAtom **, &cx->tempPool, paramsize); - if (!params) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - memset(params, 0, paramsize); - 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((uint16) sprop->shortid < nargs); - JS_ASSERT(JSID_IS_ATOM(sprop->id)); - params[(uint16) sprop->shortid] = JSID_TO_ATOM(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->interpreted && fun->object) { - oldscope = jp->scope; - jp->scope = scope; - ok = js_DecompileScript(jp, fun->u.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) { - if (!jp->grouped && (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, type; - intN depth; - jssrcnote *sn; - uintN len, off; - JSPrinter *jp; - JSString *name; - - for (fp = cx->fp; fp && !fp->script; fp = fp->down) - continue; - 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->interpreted)); - 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 && SN_TYPE(sn) != SRC_PCDELTA)) { - if (cs->token) - return JS_NewStringCopyZ(cx, cs->token); - 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) { - /* - * JOF_NAME does not imply JOF_CONST, so we must check for the - * QARG and QVAR format types and translate those to JSOP_GETARG - * or JSOP_GETVAR appropriately, instead of JSOP_NAME. - */ - type = format & JOF_TYPEMASK; - tmp[0] = (type == JOF_QARG) - ? JSOP_GETARG - : (type == JOF_QVAR) - ? JSOP_GETVAR - : 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; - } - - name = NULL; - jp = js_NewPrinter(cx, "js_DecompileValueGenerator", 0, JS_FALSE); - if (jp) { - if (fp->fun && fp->fun->object) { - JS_ASSERT(OBJ_IS_NATIVE(fp->fun->object)); - jp->scope = OBJ_SCOPE(fp->fun->object); - } - if (js_DecompileCode(jp, script, begin, len)) - name = js_GetPrinterOutput(jp); - 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 deleted file mode 100644 index 2a488f6eb..000000000 --- a/src/dom/js/jsopcode.h +++ /dev/null @@ -1,301 +0,0 @@ -/* -*- 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 -#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_INDEXCONST 8 /* arg or var index + constant pool index */ -#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_UINT24 12 /* extended unsigned 24-bit literal (index) */ -#define JOF_LITOPX 13 /* JOF_UINT24 followed by op being extended, - where op if JOF_CONST has no unsigned 16- - bit immediate operand */ -#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_DETECTING 0x2000 /* object detection flag for JSNewResolveOp */ -#define JOF_BACKPATCH 0x4000 /* backpatch placeholder during codegen */ -#define JOF_LEFTASSOC 0x8000 /* left-associative operator */ -#define JOF_DECLARING 0x10000 /* var, const, or function declaration op */ -#define JOF_XMLNAME 0x20000 /* XML name: *, a::b, @a, @a::b, etc. */ - -#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. Most scripts have relatively - * few literals, so the standard JOF_CONST format specifies a fixed 16 bits of - * immediate operand index. A script with more than 64K literals must push all - * high-indexed literals on the stack using JSOP_LITERAL, then use JOF_ELEM ops - * instead of JOF_PROP, etc. - */ -#define ATOM_INDEX_LEN 2 -#define ATOM_INDEX_HI(i) ((jsbytecode)((i) >> 8)) -#define ATOM_INDEX_LO(i) ((jsbytecode)(i)) -#define GET_ATOM_INDEX(pc) ((jsatomid)(((pc)[1] << 8) | (pc)[2])) -#define SET_ATOM_INDEX(pc,i) ((pc)[1] = ATOM_INDEX_HI(i), \ - (pc)[2] = ATOM_INDEX_LO(i)) -#define GET_ATOM(cx,script,pc) js_GetAtom((cx), &(script)->atomMap, \ - GET_ATOM_INDEX(pc)) - -/* A full atom index for JSOP_LITERAL uses 24 bits of immediate operand. */ -#define LITERAL_INDEX_LEN 3 -#define LITERAL_INDEX_HI(i) ((jsbytecode)((i) >> 16)) -#define LITERAL_INDEX_MID(i) ((jsbytecode)((i) >> 8)) -#define LITERAL_INDEX_LO(i) ((jsbytecode)(i)) -#define GET_LITERAL_INDEX(pc) ((jsatomid)(((pc)[1] << 16) | \ - ((pc)[2] << 8) | \ - (pc)[3])) -#define SET_LITERAL_INDEX(pc,i) ((pc)[1] = LITERAL_INDEX_HI(i), \ - (pc)[2] = LITERAL_INDEX_MID(i), \ - (pc)[3] = LITERAL_INDEX_LO(i)) - -/* Atom index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */ -#define ATOM_INDEX_LIMIT_LOG2 23 -#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 char js_default_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 - -extern JS_FRIEND_API(JSBool) -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 deleted file mode 100644 index 6e649413e..000000000 --- a/src/dom/js/jsopcode.tbl +++ /dev/null @@ -1,396 +0,0 @@ -/* -*- 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 128 columns: -12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 - */ - -/* 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|JOF_DETECTING) -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|JOF_DETECTING) -OPDEF(JSOP_NE, 19, "ne", "!=", 1, 2, 1, 5, JOF_BYTE|JOF_LEFTASSOC|JOF_DETECTING) -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|JOF_DETECTING) -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|JOF_DETECTING) -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|JOF_DETECTING) -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|JOF_DETECTING) -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|JOF_DETECTING) -OPDEF(JSOP_AND, 69, "and", NULL, 3, 1, 0, 0, JOF_JUMP|JOF_DETECTING) - -/* The switch bytecodes have variable length. */ -OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH|JOF_DETECTING) -OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCH|JOF_DETECTING) - -/* New, infallible/transitive identity ops. */ -OPDEF(JSOP_NEW_EQ, 72, "eq", NULL, 1, 2, 1, 5, JOF_BYTE|JOF_DETECTING) -OPDEF(JSOP_NEW_NE, 73, "ne", NULL, 1, 2, 1, 5, JOF_BYTE|JOF_DETECTING) - -/* 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|JOF_DETECTING) - -/* 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|JOF_DETECTING) -OPDEF(JSOP_INITELEM, 92, "initelem", NULL, 1, 2, 0, 0, JOF_BYTE |JOF_ELEM|JOF_DETECTING) -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|JOF_DETECTING) - -/* 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, 0, 0, JOF_JUMP) -OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 0, 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,NULL, 1, 0, 0, 0, JOF_BYTE) -OPDEF(JSOP_SETTER, 124,js_setter_str,NULL, 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|JOF_DECLARING) -OPDEF(JSOP_DEFCONST, 126,"defconst", NULL, 3, 0, 0, 0, JOF_CONST|JOF_DECLARING) -OPDEF(JSOP_DEFVAR, 127,"defvar", NULL, 3, 0, 0, 0, JOF_CONST|JOF_DECLARING) - -/* 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 - * Edition 3 catch variables. - */ -OPDEF(JSOP_INITCATCHVAR,130, "initcatchvar",NULL, 3, 1, 0, 0, JOF_CONST) - -/* 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_INDEXCONST|JOF_DECLARING) - -/* 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|JOF_DETECTING) -OPDEF(JSOP_IFNEX, 141,"ifnex", NULL, 5, 1, 0, 0, JOF_JUMPX) -OPDEF(JSOP_ORX, 142,"orx", NULL, 5, 1, 0, 0, JOF_JUMPX|JOF_DETECTING) -OPDEF(JSOP_ANDX, 143,"andx", NULL, 5, 1, 0, 0, JOF_JUMPX|JOF_DETECTING) -OPDEF(JSOP_GOSUBX, 144,"gosubx", NULL, 5, 0, 0, 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|JOF_DETECTING) -OPDEF(JSOP_LOOKUPSWITCHX, 148,"lookupswitchx",NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCHX|JOF_DETECTING) - -/* 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) - -/* Set cx->throwing where cx->exception was already set, to trigger rethrow. */ -OPDEF(JSOP_THROWING, 151,"throwing", NULL, 1, 0, 0, 0, JOF_BYTE) - -/* 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) - -/* Optimized global variable ops (we don't bother doing a JSOP_FORGVAR op). */ -OPDEF(JSOP_GETGVAR, 154,"getgvar", NULL, 3, 0, 1, 12, JOF_CONST|JOF_NAME) -OPDEF(JSOP_SETGVAR, 155,"setgvar", NULL, 3, 1, 1, 1, JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING|JOF_DETECTING) -OPDEF(JSOP_INCGVAR, 156,"incgvar", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_INC) -OPDEF(JSOP_DECGVAR, 157,"decgvar", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_DEC) -OPDEF(JSOP_GVARINC, 158,"gvarinc", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_INC|JOF_POST) -OPDEF(JSOP_GVARDEC, 159,"gvardec", NULL, 3, 0, 1, 10, JOF_CONST|JOF_NAME|JOF_DEC|JOF_POST) - -/* Regular expression literal requiring special "fork on exec" handling. */ -OPDEF(JSOP_REGEXP, 160,"regexp", NULL, 3, 0, 1, 12, JOF_CONST) - -/* XML (ECMA-357, a.k.a. "E4X") support. */ -OPDEF(JSOP_DEFXMLNS, 161,"defxmlns", NULL, 1, 1, 0, 0, JOF_BYTE) -OPDEF(JSOP_ANYNAME, 162,"anyname", NULL, 1, 0, 1, 12, JOF_BYTE|JOF_XMLNAME) -OPDEF(JSOP_QNAMEPART, 163,"qnamepart", NULL, 3, 0, 1, 12, JOF_CONST|JOF_XMLNAME) -OPDEF(JSOP_QNAMECONST, 164,"qnameconst", NULL, 3, 1, 1, 12, JOF_CONST|JOF_XMLNAME) -OPDEF(JSOP_QNAME, 165,"qname", NULL, 1, 2, 1, 0, JOF_BYTE|JOF_XMLNAME) -OPDEF(JSOP_TOATTRNAME, 166,"toattrname", NULL, 1, 1, 1, 12, JOF_BYTE|JOF_XMLNAME) -OPDEF(JSOP_TOATTRVAL, 167,"toattrval", NULL, 1, 1, 1, 12, JOF_BYTE) -OPDEF(JSOP_ADDATTRNAME, 168,"addattrname",NULL, 1, 2, 1, 8, JOF_BYTE) -OPDEF(JSOP_ADDATTRVAL, 169,"addattrval", NULL, 1, 2, 1, 8, JOF_BYTE) -OPDEF(JSOP_BINDXMLNAME, 170,"bindxmlname",NULL, 1, 1, 2, 0, JOF_BYTE|JOF_XMLNAME|JOF_SET|JOF_ASSIGNING) -OPDEF(JSOP_SETXMLNAME, 171,"setxmlname", NULL, 1, 3, 1, 1, JOF_BYTE|JOF_XMLNAME|JOF_SET|JOF_ASSIGNING|JOF_DETECTING) -OPDEF(JSOP_XMLNAME, 172,"xmlname", NULL, 1, 1, 1, 12, JOF_BYTE|JOF_XMLNAME) -OPDEF(JSOP_DESCENDANTS, 173,"descendants",NULL, 1, 2, 1, 11, JOF_BYTE) -OPDEF(JSOP_FILTER, 174,"filter", NULL, 3, 1, 1, 11, JOF_JUMP) -OPDEF(JSOP_ENDFILTER, 175,"endfilter", NULL, 1, 1, 0, 0, JOF_BYTE) -OPDEF(JSOP_TOXML, 176,"toxml", NULL, 1, 1, 1, 12, JOF_BYTE) -OPDEF(JSOP_TOXMLLIST, 177,"toxmllist", NULL, 1, 1, 1, 12, JOF_BYTE) -OPDEF(JSOP_XMLTAGEXPR, 178,"xmltagexpr", NULL, 1, 1, 1, 0, JOF_BYTE) -OPDEF(JSOP_XMLELTEXPR, 179,"xmleltexpr", NULL, 1, 1, 1, 0, JOF_BYTE) -OPDEF(JSOP_XMLOBJECT, 180,"xmlobject", NULL, 3, 0, 1, 12, JOF_CONST) -OPDEF(JSOP_XMLCDATA, 181,"xmlcdata", NULL, 3, 0, 1, 12, JOF_CONST) -OPDEF(JSOP_XMLCOMMENT, 182,"xmlcomment", NULL, 3, 0, 1, 12, JOF_CONST) -OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 3, 1, 1, 12, JOF_CONST) -OPDEF(JSOP_GETMETHOD, 184,"getmethod", NULL, 3, 1, 1, 11, JOF_CONST|JOF_PROP) -OPDEF(JSOP_GETFUNNS, 185,"getfunns", NULL, 1, 0, 1, 12, JOF_BYTE) -OPDEF(JSOP_FOREACH, 186,"foreach", NULL, 1, 0, 0, 0, JOF_BYTE) -OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_DEL) - -/* - * Opcodes for extended literal addressing, using unsigned 24-bit immediate - * operands to hold integer operands (JSOP_UINT24), extended atom indexes in - * script->atomMap (JSOP_LITERAL, JSOP_FINDNAME), and ops prefixed by such - * atom index immediates (JSOP_LITOPX). See jsemit.c, EmitAtomIndexOp. - */ -OPDEF(JSOP_UINT24, 188,"uint24", NULL, 4, 0, 1, 12, JOF_UINT24) -OPDEF(JSOP_LITERAL, 189,"literal", NULL, 4, 0, 1, 12, JOF_UINT24) -OPDEF(JSOP_FINDNAME, 190,"findname", NULL, 4, 0, 2, 0, JOF_UINT24) -OPDEF(JSOP_LITOPX, 191,"litopx", NULL, 5, 0, 0, 12, JOF_LITOPX) - -/* - * Opcodes to help the decompiler deal with XML. - */ -OPDEF(JSOP_STARTXML, 192,"startxml", NULL, 1, 0, 0, 0, JOF_BYTE) -OPDEF(JSOP_STARTXMLEXPR, 193,"startxmlexpr",NULL, 1, 0, 0, 0, JOF_BYTE) -OPDEF(JSOP_SETMETHOD, 194,"setmethod", NULL, 3, 2, 1, 1, JOF_CONST|JOF_PROP) diff --git a/src/dom/js/jsosdep.h b/src/dom/js/jsosdep.h deleted file mode 100644 index e9c4a5534..000000000 --- a/src/dom/js/jsosdep.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- 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_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 deleted file mode 100644 index ede1221b8..000000000 --- a/src/dom/js/jsotypes.h +++ /dev/null @@ -1,202 +0,0 @@ -/* -*- 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 PRs. - * 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 - -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 -#else -typedef JSUintn uint; -#endif - -typedef JSUintn uintn; -typedef JSUint64 uint64; -#if !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 -#else -typedef JSInt64 int64; - -/* /usr/include/model.h on HP-UX defines int8, int16, and int32 */ -#ifdef HPUX -#include -#else -#if !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 - -#endif /* !defined(PROTYPES_H) */ diff --git a/src/dom/js/jsparse.c b/src/dom/js/jsparse.c deleted file mode 100644 index 1438f35a2..000000000 --- a/src/dom/js/jsparse.c +++ /dev/null @@ -1,4880 +0,0 @@ -/* -*- 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. - */ -#include "jsstddef.h" -#include -#include -#include -#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" - -#if JS_HAS_XML_SUPPORT -#include "jsxml.h" -#endif - -/* - * JS parsers, from lowest to highest precedence. - * - * Each parser takes a context, a token stream, and a tree context struct. - * Each returns a parse node tree or null on error. - */ - -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, JSREPORT_TS | 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, JSREPORT_TS | 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 JSParseNode * -RecycleTree(JSParseNode *pn, JSTreeContext *tc) -{ - JSParseNode *next; - - if (!pn) - return NULL; - JS_ASSERT(pn != tc->nodeList); /* catch back-to-back dup recycles */ - next = pn->pn_next; - pn->pn_next = tc->nodeList; - tc->nodeList = pn; -#ifdef METER_PARSENODES - recyclednodes++; -#endif - return next; -} - -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; - } - } -#ifdef METER_PARSENODES - if (pn) { - parsenodes++; - if (parsenodes - recyclednodes > maxparsenodes) - maxparsenodes = parsenodes - recyclednodes; - } -#endif - return pn; -} - -/* - * Allocate a JSParseNode from cx's temporary arena. - */ -static JSParseNode * -NewParseNode(JSContext *cx, JSTokenStream *ts, JSParseNodeArity arity, - JSTreeContext *tc) -{ - JSParseNode *pn; - JSToken *tp; - - pn = NewOrRecycledNode(cx, tc); - if (!pn) - return NULL; - tp = &CURRENT_TOKEN(ts); - pn->pn_type = tp->type; - pn->pn_pos = tp->pos; - pn->pn_op = JSOP_NOP; - pn->pn_arity = arity; - pn->pn_next = NULL; -#if JS_HAS_XML_SUPPORT - pn->pn_ts = ts; -#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); - 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; - left->pn_pos.end = right->pn_pos.end; - 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; -#if JS_HAS_XML_SUPPORT - pn->pn_ts = NULL; -#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, JSREPORT_TS | 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, - JSREPORT_TS | - 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; - if (fp) { - frame.flags = fp->flags & (JSFRAME_SPECIAL | JSFRAME_COMPILE_N_GO | - JSFRAME_SCRIPT_OBJECT); - } - 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_NewGCThing), 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, JSREPORT_TS | 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; - uint32 flags; - 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; - if (fp) { - frame.flags = fp->flags & (JSFRAME_SPECIAL | JSFRAME_COMPILE_N_GO | - JSFRAME_SCRIPT_OBJECT); - } - cx->fp = &frame; - } - flags = cx->fp->flags; - cx->fp->flags = flags | - (JS_HAS_COMPILE_N_GO_OPTION(cx) - ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO - : JSFRAME_COMPILING); - - /* 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, JSREPORT_TS | 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->flags = flags; - 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). - */ -#define ENDS_IN_OTHER 0 -#define ENDS_IN_RETURN 1 -#define ENDS_IN_BREAK 2 - -static int -HasFinalReturn(JSParseNode *pn) -{ - uintN rv, rv2, hasDefault; - JSParseNode *pn2, *pn3; - - switch (pn->pn_type) { - case TOK_LC: - if (!pn->pn_head) - return ENDS_IN_OTHER; - return HasFinalReturn(PN_LAST(pn)); - - case TOK_IF: - rv = HasFinalReturn(pn->pn_kid2); - if (pn->pn_kid3) - rv &= HasFinalReturn(pn->pn_kid3); - return rv; - -#if JS_HAS_SWITCH_STATEMENT - case TOK_SWITCH: - rv = ENDS_IN_RETURN; - hasDefault = ENDS_IN_OTHER; - for (pn2 = pn->pn_kid2->pn_head; rv && pn2; pn2 = pn2->pn_next) { - if (pn2->pn_type == TOK_DEFAULT) - hasDefault = ENDS_IN_RETURN; - pn3 = pn2->pn_right; - JS_ASSERT(pn3->pn_type == TOK_LC); - if (pn3->pn_head) { - rv2 = HasFinalReturn(PN_LAST(pn3)); - if (rv2 == ENDS_IN_OTHER && pn2->pn_next) - /* Falling through to next case or default. */; - else - rv &= rv2; - } - } - /* If a final switch has no default case, we judge it harshly. */ - rv &= hasDefault; - return rv; -#endif /* JS_HAS_SWITCH_STATEMENT */ - - case TOK_BREAK: - return ENDS_IN_BREAK; - - case TOK_WITH: - return HasFinalReturn(pn->pn_right); - - case TOK_RETURN: - return ENDS_IN_RETURN; - - case TOK_COLON: - return HasFinalReturn(pn->pn_expr); - -#if JS_HAS_EXCEPTIONS - case TOK_THROW: - return ENDS_IN_RETURN; - - case TOK_TRY: - /* If we have a finally block that returns, we are done. */ - if (pn->pn_kid3) { - rv = HasFinalReturn(pn->pn_kid3); - if (rv == ENDS_IN_RETURN) - return rv; - } - - /* Else check the try block and any and all catch statements. */ - rv = HasFinalReturn(pn->pn_kid1); - if (pn->pn_kid2) - rv &= HasFinalReturn(pn->pn_kid2); - return rv; - - case TOK_CATCH: - /* Check this block's code and iterate over further catch blocks. */ - rv = HasFinalReturn(pn->pn_kid3); - for (pn2 = pn->pn_kid2; pn2; pn2 = pn2->pn_kid2) - rv &= HasFinalReturn(pn2->pn_kid3); - return rv; -#endif - - default: - return ENDS_IN_OTHER; - } -} - -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, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_NO_RETURN_VALUE, name); - } else { - ok = js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_ANON_NO_RETURN_VALUE); - } - return ok; -} - -static JSBool -CheckFinalReturn(JSContext *cx, JSTokenStream *ts, JSParseNode *pn) -{ - return HasFinalReturn(pn) == ENDS_IN_RETURN || 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; - if (fp) - frame.flags = fp->flags & JSFRAME_COMPILE_N_GO; - 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 | TCF_HAS_DEFXMLNS)); - return pn; -} - -/* - * Compile a JS function body, which might appear as the value of an event - * handler attribute in an HTML 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(¬ePool, "note", 1024, sizeof(jssrcnote)); - if (!js_InitCodeGenerator(cx, &funcg, &codePool, ¬ePool, - 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. */ - 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; - frame.flags = JS_HAS_COMPILE_N_GO_OPTION(cx) - ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO - : JSFRAME_COMPILING; - 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->u.script = js_NewScriptFromCG(cx, &funcg, fun); - if (!fun->u.script) { - ok = JS_FALSE; - } else { - fun->interpreted = JS_TRUE; - 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(¬ePool); - return ok; -} - -static JSParseNode * -FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool lambda) -{ - JSOp op, prevop; - JSParseNode *pn, *body, *result; - JSAtom *funAtom, *objAtom, *argAtom; - JSStackFrame *fp; - JSObject *varobj, *pobj; - JSAtomListElement *ale; - JSProperty *prop; - JSFunction *fun; - uintN dupflag; - JSBool ok; - JSTreeContext funtc; - - /* Make a TOK_FUNCTION node. */ -#if JS_HAS_GETTER_SETTER - op = CURRENT_TOKEN(ts).t_op; -#endif - pn = NewParseNode(cx, ts, PN_FUNC, tc); - if (!pn) - return NULL; - - /* Scan the optional function name into funAtom. */ - funAtom = js_MatchToken(cx, ts, TOK_NAME) ? CURRENT_TOKEN(ts).t_atom : NULL; -#if !JS_HAS_LEXICAL_CLOSURE - if (!funAtom && !lambda) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); - return NULL; - } -#endif - - /* Find the nearest variable-declaring scope and use it as our parent. */ - fp = cx->fp; - varobj = fp->varobj; - - /* - * 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, - (prevop != JSOP_DEFCONST) - ? JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT - : JSREPORT_TS | 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 BindNameToSlot can optimize a JSOP_NAME into a - * JSOP_GETVAR bytecode). - */ - if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) { - JSScopeProperty *sprop; - - /* - * Define a property on the outer function so that BindNameToSlot - * can properly optimize accesses. - */ - JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass); - JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj)); - if (!js_LookupHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom), - &pobj, &prop)) { - return NULL; - } - if (prop) - OBJ_DROP_PROPERTY(cx, pobj, prop); - sprop = NULL; - if (!prop || - pobj != varobj || - (sprop = (JSScopeProperty *)prop, - sprop->getter != js_GetLocalVariable)) { - uintN sflags; - - /* - * Use SPROP_IS_DUPLICATE if there is a formal argument of the - * same name, so the decompiler can find the parameter name. - */ - sflags = (sprop && sprop->getter == js_GetArgument) - ? SPROP_IS_DUPLICATE | SPROP_HAS_SHORTID - : SPROP_HAS_SHORTID; - if (!js_AddHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom), - js_GetLocalVariable, - js_SetLocalVariable, - SPROP_INVALID_SLOT, - JSPROP_PERMANENT | JSPROP_SHARED, - sflags, fp->fun->nvars)) { - return NULL; - } - if (fp->fun->nvars == JS_BITMASK(16)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TOO_MANY_FUN_VARS); - return NULL; - } - fp->fun->nvars++; - } - } -#endif - } - - fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, varobj, - funAtom); - if (!fun) - return NULL; -#if JS_HAS_GETTER_SETTER - if (op != JSOP_NOP) - fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER; -#endif - - - /* - * Set interpreted early so js_EmitTree can test it to decide whether to - * eliminate useless expressions. - */ - fun->interpreted = JS_TRUE; - - /* - * Atomize fun->object early to protect against a last-ditch GC under - * js_LookupHiddenProperty. - * - * Absent use of the new scoped local GC roots API around compiler calls, - * we need to atomize here to protect against a GC activation. Atoms are - * protected from GC during compilation by the JS_FRIEND_API entry points - * in this file. There doesn't seem to be any gain in switching from the - * atom-keeping method to the bulkier, slower scoped local roots method. - */ - objAtom = js_AtomizeObject(cx, fun->object, 0); - if (!objAtom) - return NULL; - - /* 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_LookupHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom), - &pobj, &prop)) { - return NULL; - } - dupflag = 0; - if (prop) { - ok = JS_TRUE; - if (pobj == fun->object && - ((JSScopeProperty *) prop)->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, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_DUPLICATE_FORMAL, - name); - - dupflag = SPROP_IS_DUPLICATE; - } - OBJ_DROP_PROPERTY(cx, pobj, prop); - if (!ok) - return NULL; - prop = NULL; - } - if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom), - js_GetArgument, js_SetArgument, - SPROP_INVALID_SLOT, - JSPROP_PERMANENT | JSPROP_SHARED, - dupflag | SPROP_HAS_SHORTID, - fun->nargs)) { - return NULL; - } - if (fun->nargs == JS_BITMASK(16)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TOO_MANY_FUN_ARGS); - 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 - - result = pn; -#if JS_HAS_LEXICAL_CLOSURE - if (lambda) { - /* - * ECMA ed. 3 standard: function expression, possibly anonymous. - */ - op = funAtom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ; - } else if (!funAtom) { - /* - * If this anonymous function definition is *not* embedded within a - * larger expression, we treat it as an expression statement, not as - * a function declaration -- and not as a syntax error (as ECMA-262 - * Edition 3 would have it). Backward compatibility trumps all. - */ - result = NewParseNode(cx, ts, PN_UNARY, tc); - if (!result) - return NULL; - result->pn_type = TOK_SEMI; - result->pn_pos = pn->pn_pos; - result->pn_kid = pn; - op = 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; - - pn->pn_funAtom = objAtom; - pn->pn_op = op; - pn->pn_body = body; - pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS); - pn->pn_tryCount = funtc.tryCount; - TREE_CONTEXT_FINISH(&funtc); - return result; -} - -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, ts, PN_LIST, tc); - if (!pn) - return NULL; - PN_INIT_LIST(pn); - - ts->flags |= TSF_OPERAND; - while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) { - ts->flags &= ~TSF_OPERAND; - pn2 = Statement(cx, ts, tc); - if (!pn2) { - if (ts->flags & TSF_EOF) - ts->flags |= TSF_UNEXPECTED_EOF; - return NULL; - } - ts->flags |= TSF_OPERAND; - - /* 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_OPERAND; - 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 = !JS_VERSION_IS_ECMA(cx); - if (!js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | - 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; - JSTokenType tt; - - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME); - pn = NewParseNode(cx, 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_OPERAND; - while ((tt = js_GetToken(cx, ts)) == TOK_DOT || tt == TOK_LB) { - ts->flags &= ~TSF_OPERAND; - if (pn->pn_op == JSOP_IMPORTALL) - goto bad_import; - - if (tt == TOK_DOT) { - pn2 = NewParseNode(cx, 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 binary node. */ - pn2 = NewBinary(cx, tt, JSOP_GETELEM, pn, Expr(cx, ts, tc), tc); - if (!pn2) - return NULL; - - MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); - } - - pn = pn2; - ts->flags |= TSF_OPERAND; - } - ts->flags &= ~TSF_OPERAND; - 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, JSREPORT_TS | 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; - - CHECK_RECURSION(); - - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - -#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, ts, PN_LIST, tc); - if (!pn) - return NULL; - PN_INIT_LIST(pn); - if (js_MatchToken(cx, ts, TOK_STAR)) { - pn2 = NewParseNode(cx, 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, 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, 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: -#if JS_HAS_XML_SUPPORT - if (js_PeekToken(cx, ts) == TOK_DBLCOLON) - goto expression; -#endif - return FunctionStmt(cx, ts, tc); - - case TOK_IF: - /* An IF node has three kids: condition, then, and optional else. */ - pn = NewParseNode(cx, 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, 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, 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, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_TOO_MANY_DEFAULTS); - return NULL; - } - seenDefault = JS_TRUE; - /* fall through */ - - case TOK_CASE: - pn3 = NewParseNode(cx, 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, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_TOO_MANY_CASES); - return NULL; - } - break; - - case TOK_ERROR: - return NULL; - - default: - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_SWITCH); - return NULL; - } - MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); - - pn4 = NewParseNode(cx, ts, PN_LIST, tc); - if (!pn4) - return NULL; - pn4->pn_type = TOK_LC; - PN_INIT_LIST(pn4); - ts->flags |= TSF_OPERAND; - while ((tt = js_PeekToken(cx, ts)) != TOK_RC && - tt != TOK_CASE && tt != TOK_DEFAULT) { - ts->flags &= ~TSF_OPERAND; - 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); - ts->flags |= TSF_OPERAND; - } - ts->flags &= ~TSF_OPERAND; - - /* 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, 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, 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; - if ((cx->version & JSVERSION_MASK) != JSVERSION_ECMA_3) { - /* - * All legacy and extended versions must do automatic semicolon - * insertion after do-while. See the testcase and discussion in - * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. - */ - (void) js_MatchToken(cx, ts, TOK_SEMI); - return pn; - } - 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, ts, PN_BINARY, tc); - if (!pn) - return NULL; - js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1); - -#if JS_HAS_XML_SUPPORT - pn->pn_op = JSOP_NOP; - if (js_MatchToken(cx, ts, TOK_NAME)) { - if (CURRENT_TOKEN(ts).t_atom == cx->runtime->atomState.eachAtom) - pn->pn_op = JSOP_FOREACH; - else - js_UngetToken(ts); - } -#endif - - MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - if (tt == TOK_SEMI) { -#if JS_HAS_XML_SUPPORT - if (pn->pn_op == JSOP_FOREACH) - goto bad_for_each; -#endif - - /* 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. */ - while (pn1->pn_type == TOK_RP) - pn1 = pn1->pn_kid; - 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 && -#if JS_HAS_LVALUE_RETURN - pn1->pn_type != TOK_LP && -#endif -#if JS_HAS_XML_SUPPORT - (pn1->pn_type != TOK_UNARYOP || - pn1->pn_op != JSOP_XMLNAME) && -#endif - pn1->pn_type != TOK_LB)) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); - return NULL; - } - - if (pn1->pn_type == TOK_VAR) { - /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */ - pn1->pn_extra |= PNX_FORINVAR; - - /* Generate a final POP only if the var has an initializer. */ - pn2 = pn1->pn_head; - if (pn2->pn_expr) - pn1->pn_extra |= PNX_POPVAR; - } else { - pn2 = pn1; -#if JS_HAS_LVALUE_RETURN - if (pn2->pn_type == TOK_LP) - pn2->pn_op = JSOP_SETCALL; -#endif -#if JS_HAS_XML_SUPPORT - if (pn2->pn_type == TOK_UNARYOP) - pn2->pn_op = JSOP_BINDXMLNAME; -#endif - } - - /* 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 { -#if JS_HAS_XML_SUPPORT - if (pn->pn_op == JSOP_FOREACH) - goto bad_for_each; -#endif - - /* Parse the loop condition or null into pn2. */ - MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - if (tt == 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); - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - if (tt == 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, 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_XML_SUPPORT - bad_for_each: - js_ReportCompileErrorNumber(cx, pn, - JSREPORT_PN | JSREPORT_ERROR, - JSMSG_BAD_FOR_EACH_LOOP); - return NULL; -#endif - -#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, 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, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_CATCH_AFTER_GENERAL); - return NULL; - } - - /* - * legal catch forms are: - * catch (v) - * catch (v if ) - * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD) - */ - (void) js_GetToken(cx, ts); /* eat `catch' */ - pn2 = NewParseNode(cx, 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, 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, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_CATCH_OR_FINALLY); - return NULL; - } - tc->tryCount++; - return pn; - } - - case TOK_THROW: - pn = NewParseNode(cx, ts, PN_UNARY, tc); - if (!pn) - return NULL; - - /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ - ts->flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(cx, ts); - ts->flags &= ~TSF_OPERAND; - if (tt == TOK_ERROR) - return NULL; - if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); - 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, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_CATCH_WITHOUT_TRY); - return NULL; - - case TOK_FINALLY: - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_FINALLY_WITHOUT_TRY); - return NULL; - -#endif /* JS_HAS_EXCEPTIONS */ - - case TOK_BREAK: - pn = NewParseNode(cx, 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, - JSREPORT_TS | 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, - JSREPORT_TS | 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, 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, - JSREPORT_TS | 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, - JSREPORT_TS | - JSREPORT_ERROR, - JSMSG_BAD_CONTINUE); - return NULL; - } - break; - } - } else { - stmt2 = stmt; - } - } - } else { - for (; ; stmt = stmt->down) { - if (!stmt) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | 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, 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); - - 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 |= PNX_POPVAR; - break; - - case TOK_RETURN: - if (!(tc->flags & TCF_IN_FUNCTION)) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_RETURN); - return NULL; - } - pn = NewParseNode(cx, ts, PN_UNARY, tc); - if (!pn) - return NULL; - - /* This is ugly, but we don't want to require a semicolon. */ - ts->flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(cx, ts); - ts->flags &= ~TSF_OPERAND; - 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, 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, ts, PN_NULLARY, tc); - if (!pn) - return NULL; - pn->pn_type = TOK_DEBUGGER; - tc->flags |= TCF_FUN_HEAVYWEIGHT; - break; -#endif /* JS_HAS_DEBUGGER_KEYWORD */ - -#if JS_HAS_XML_SUPPORT - case TOK_DEFAULT: - pn = NewParseNode(cx, ts, PN_UNARY, tc); - if (!pn) - return NULL; - if (!js_MatchToken(cx, ts, TOK_NAME) || - CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.xmlAtom || - !js_MatchToken(cx, ts, TOK_NAME) || - CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.namespaceAtom || - !js_MatchToken(cx, ts, TOK_ASSIGN) || - CURRENT_TOKEN(ts).t_op != JSOP_NOP) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_DEFAULT_XML_NAMESPACE); - return NULL; - } - pn2 = Expr(cx, ts, tc); - if (!pn2) - return NULL; - pn->pn_op = JSOP_DEFXMLNS; - pn->pn_pos.end = pn2->pn_pos.end; - pn->pn_kid = pn2; - tc->flags |= TCF_HAS_DEFXMLNS; - break; -#endif - - case TOK_ERROR: - return NULL; - - default: -#if JS_HAS_XML_SUPPORT - expression: -#endif - 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, - JSREPORT_TS | 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, - JSREPORT_TS | 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, 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, JSREPORT_TS | 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, ts, PN_LIST, tc); - if (!pn) - return NULL; - pn->pn_op = CURRENT_TOKEN(ts).t_op; - 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_DEFVAR || prevop != JSOP_DEFVAR - : pn->pn_op == JSOP_DEFCONST || prevop == JSOP_DEFCONST) { - const char *name = js_AtomToPrintableString(cx, atom); - if (!name || - !js_ReportCompileErrorNumber(cx, ts, - (pn->pn_op != JSOP_DEFCONST && - prevop != JSOP_DEFCONST) - ? JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT - : JSREPORT_TS | 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, 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_PERMANENT | JSPROP_READONLY - : JSPROP_PERMANENT; - PN_APPEND(pn, pn2); - - if (!fun) { - /* Don't lookup global variables at compile time. */ - prop = NULL; - } else if (OBJ_IS_NATIVE(obj)) { - if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), - &pobj, &prop)) { - return NULL; - } - } else { - if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop)) - return NULL; - } - if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) { - sprop = (JSScopeProperty *)prop; - 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, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_REDECLARED_PARAM, - name); - ok = JS_FALSE; - } else { - currentGetter = js_GetArgument; - currentSetter = js_SetArgument; - ok = js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | - 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) && - (uint16) 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) && - (uint16) 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_AddHiddenProperty(cx, obj, ATOM_TO_JSID(atom), - currentGetter, currentSetter, - SPROP_INVALID_SLOT, - pn2->pn_attrs | JSPROP_SHARED, - SPROP_HAS_SHORTID, fun->nvars)) { - return NULL; - } - if (fun->nvars == JS_BITMASK(16)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TOO_MANY_FUN_VARS); - return NULL; - } - fun->nvars++; - } - } - - if (js_MatchToken(cx, ts, TOK_ASSIGN)) { - if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | 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, 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 = (pn2->pn_op == JSOP_GETMETHOD) - ? JSOP_SETMETHOD - : 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 -#if JS_HAS_XML_SUPPORT - case TOK_UNARYOP: - if (pn2->pn_op == JSOP_XMLNAME) { - pn2->pn_op = JSOP_SETXMLNAME; - break; - } - /* FALL THROUGH */ -#endif - default: - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | 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, 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 -#if JS_HAS_XML_SUPPORT - (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) && -#endif - kid->pn_type != TOK_LB) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | 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: - JS_ASSERT(kid->pn_op == JSOP_CALL); - kid->pn_op = JSOP_SETCALL; - /* FALL THROUGH */ -#endif -#if JS_HAS_XML_SUPPORT - case TOK_UNARYOP: - if (kid->pn_op == JSOP_XMLNAME) - kid->pn_op = JSOP_SETXMLNAME; - /* FALL THROUGH */ -#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; - - CHECK_RECURSION(); - - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - - switch (tt) { - case TOK_UNARYOP: - case TOK_PLUS: - case TOK_MINUS: - pn = NewParseNode(cx, 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, 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, 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, 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_OPERAND; - matched = js_MatchToken(cx, ts, TOK_RP); - ts->flags &= ~TSF_OPERAND; - 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, JSREPORT_TS | 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_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - if (tt == TOK_NEW) { - (void) js_GetToken(cx, ts); - - pn = NewParseNode(cx, 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; - - if (pn->pn_type == TOK_ANYNAME || - pn->pn_type == TOK_AT || - pn->pn_type == TOK_DBLCOLON) { - pn2 = NewOrRecycledNode(cx, tc); - if (!pn2) - return NULL; - pn2->pn_type = TOK_UNARYOP; - pn2->pn_pos = pn->pn_pos; - pn2->pn_op = JSOP_XMLNAME; - pn2->pn_arity = PN_UNARY; - pn2->pn_kid = pn; - pn2->pn_next = NULL; -#if JS_HAS_XML_SUPPORT - pn2->pn_ts = ts; -#endif - pn = pn2; - } - } - - while ((tt = js_GetToken(cx, ts)) > TOK_EOF) { - if (tt == TOK_DOT) { - pn2 = NewParseNode(cx, ts, PN_NAME, tc); - if (!pn2) - return NULL; -#if JS_HAS_XML_SUPPORT - pn3 = PrimaryExpr(cx, ts, tc); - if (!pn3) - return NULL; - tt = pn3->pn_type; - if (tt == TOK_NAME || - (tt == TOK_DBLCOLON && - pn3->pn_arity == PN_NAME && - pn3->pn_expr->pn_type == TOK_FUNCTION)) { - pn2->pn_op = (tt == TOK_NAME) ? JSOP_GETPROP : JSOP_GETMETHOD; - pn2->pn_expr = pn; - pn2->pn_atom = pn3->pn_atom; - RecycleTree(pn3, tc); - } else { - if (TOKEN_TYPE_IS_XML(tt)) { - pn2->pn_type = TOK_LB; - pn2->pn_op = JSOP_GETELEM; - } else if (tt == TOK_RP) { - JSParseNode *group = pn3; - - /* Recycle the useless TOK_RP/JSOP_GROUP node. */ - pn3 = group->pn_kid; - group->pn_kid = NULL; - RecycleTree(group, tc); - pn2->pn_type = TOK_FILTER; - pn2->pn_op = JSOP_FILTER; - } else { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); - return NULL; - } - pn2->pn_arity = PN_BINARY; - pn2->pn_left = pn; - pn2->pn_right = pn3; - } -#else - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT); - pn2->pn_op = JSOP_GETPROP; - pn2->pn_expr = pn; - pn2->pn_atom = CURRENT_TOKEN(ts).t_atom; -#endif - pn2->pn_pos.begin = pn->pn_pos.begin; - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; -#if JS_HAS_XML_SUPPORT - } else if (tt == TOK_DBLDOT) { - pn2 = NewParseNode(cx, ts, PN_BINARY, tc); - if (!pn2) - return NULL; - pn3 = PrimaryExpr(cx, ts, tc); - if (!pn3) - return NULL; - tt = pn3->pn_type; - if (tt == TOK_NAME) { - pn3->pn_type = TOK_STRING; - pn3->pn_arity = PN_NULLARY; - pn3->pn_op = JSOP_STRING; - } else if (!TOKEN_TYPE_IS_XML(tt)) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); - return NULL; - } - pn2->pn_op = JSOP_DESCENDANTS; - pn2->pn_left = pn; - pn2->pn_right = pn3; - pn2->pn_pos.begin = pn->pn_pos.begin; - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; -#endif - } else if (tt == TOK_LB) { - pn2 = NewParseNode(cx, 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, 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 = CURRENT_TOKEN(ts).pos.end; - } else { - js_UngetToken(ts); - return pn; - } - - pn = pn2; - } - if (tt == TOK_ERROR) - return NULL; - return pn; -} - -static JSParseNode * -BracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - uintN oldflags; - JSParseNode *pn; - -#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 - pn = Expr(cx, ts, tc); -#if JS_HAS_IN_OPERATOR - tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS); -#endif - return pn; -} - -#if JS_HAS_XML_SUPPORT - -static JSParseNode * -EndBracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - JSParseNode *pn; - - pn = BracketedExpr(cx, ts, tc); - if (!pn) - return NULL; - - MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ATTR_EXPR); - return pn; -} - -/* - * From the ECMA-357 grammar in 11.1.1 and 11.1.2: - * - * AttributeIdentifier: - * @ PropertySelector - * @ QualifiedIdentifier - * @ [ Expression ] - * - * PropertySelector: - * Identifier - * * - * - * QualifiedIdentifier: - * PropertySelector :: PropertySelector - * PropertySelector :: [ Expression ] - * - * We adapt AttributeIdentifier and QualifiedIdentier to be LL(1), like so: - * - * AttributeIdentifier: - * @ QualifiedIdentifier - * @ [ Expression ] - * - * PropertySelector: - * Identifier - * * - * - * QualifiedIdentifier: - * PropertySelector :: PropertySelector - * PropertySelector :: [ Expression ] - * PropertySelector - * - * Since PrimaryExpression: Identifier in ECMA-262 and we want the semantics - * for that rule to result in a name node, but extend the grammar to include - * PrimaryExpression: QualifiedIdentifier, we factor further: - * - * QualifiedIdentifier: - * PropertySelector QualifiedSuffix - * - * QualifiedSuffix: - * :: PropertySelector - * :: [ Expression ] - * /nothing/ - * - * And use this production instead of PrimaryExpression: QualifiedIdentifier: - * - * PrimaryExpression: - * Identifier QualifiedSuffix - * - * We hoists the :: match into callers of QualifiedSuffix, in order to tweak - * PropertySelector vs. Identifier pn_arity, pn_op, and other members. - */ -static JSParseNode * -PropertySelector(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - JSParseNode *pn; - - pn = NewParseNode(cx, ts, PN_NULLARY, tc); - if (!pn) - return NULL; - if (pn->pn_type == TOK_STAR) { - pn->pn_type = TOK_ANYNAME; - pn->pn_op = JSOP_ANYNAME; - pn->pn_atom = cx->runtime->atomState.starAtom; - } else { - JS_ASSERT(pn->pn_type == TOK_NAME); - pn->pn_op = JSOP_QNAMEPART; - pn->pn_arity = PN_NAME; - pn->pn_atom = CURRENT_TOKEN(ts).t_atom; - pn->pn_expr = NULL; - pn->pn_slot = -1; - pn->pn_attrs = 0; - } - return pn; -} - -static JSParseNode * -QualifiedSuffix(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, - JSTreeContext *tc) -{ - JSParseNode *pn2, *pn3; - JSTokenType tt; - - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_DBLCOLON); - pn2 = NewParseNode(cx, ts, PN_NAME, tc); - if (!pn2) - return NULL; - - /* Left operand of :: must be evaluated if it is an identifier. */ - if (pn->pn_op == JSOP_QNAMEPART) - pn->pn_op = JSOP_NAME; - - tt = js_GetToken(cx, ts); - if (tt == TOK_STAR || tt == TOK_NAME) { - /* Inline and specialize PropertySelector for JSOP_QNAMECONST. */ - pn2->pn_op = JSOP_QNAMECONST; - pn2->pn_atom = (tt == TOK_STAR) - ? cx->runtime->atomState.starAtom - : CURRENT_TOKEN(ts).t_atom; - pn2->pn_expr = pn; - pn2->pn_slot = -1; - pn2->pn_attrs = 0; - return pn2; - } - - if (tt != TOK_LB) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); - return NULL; - } - pn3 = EndBracketedExpr(cx, ts, tc); - if (!pn3) - return NULL; - - pn2->pn_op = JSOP_QNAME; - pn2->pn_arity = PN_BINARY; - pn2->pn_left = pn; - pn2->pn_right = pn3; - return pn2; -} - -static JSParseNode * -QualifiedIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - JSParseNode *pn; - - pn = PropertySelector(cx, ts, tc); - if (!pn) - return NULL; - if (js_MatchToken(cx, ts, TOK_DBLCOLON)) - pn = QualifiedSuffix(cx, ts, pn, tc); - return pn; -} - -static JSParseNode * -AttributeIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - JSParseNode *pn, *pn2; - JSTokenType tt; - - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_AT); - pn = NewParseNode(cx, ts, PN_UNARY, tc); - if (!pn) - return NULL; - pn->pn_op = JSOP_TOATTRNAME; - tt = js_GetToken(cx, ts); - if (tt == TOK_STAR || tt == TOK_NAME) { - pn2 = QualifiedIdentifier(cx, ts, tc); - } else if (tt == TOK_LB) { - pn2 = EndBracketedExpr(cx, ts, tc); - } else { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); - return NULL; - } - if (!pn2) - return NULL; - pn->pn_kid = pn2; - return pn; -} - -/* - * Make a TOK_LC unary node whose pn_kid is an expression. - */ -static JSParseNode * -XMLExpr(JSContext *cx, JSTokenStream *ts, JSBool inTag, JSTreeContext *tc) -{ - JSParseNode *pn, *pn2; - uintN oldflags; - - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LC); - pn = NewParseNode(cx, ts, PN_UNARY, tc); - if (!pn) - return NULL; - - /* - * Turn off XML tag mode, but don't restore it after parsing this braced - * expression. Instead, simply restore ts's old flags. This is required - * because XMLExpr is called both from within a tag, and from within text - * contained in an element, but outside of any start, end, or point tag. - */ - oldflags = ts->flags; - ts->flags = oldflags & ~TSF_XMLTAGMODE; - pn2 = Expr(cx, ts, tc); - if (!pn2) - return NULL; - - MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_XML_EXPR); - ts->flags = oldflags; - pn->pn_kid = pn2; - pn->pn_op = inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR; - return pn; -} - -/* - * Make a terminal node for oneof TOK_XMLNAME, TOK_XMLATTR, TOK_XMLSPACE, - * TOK_XMLTEXT, TOK_XMLCDATA, TOK_XMLCOMMENT, or TOK_XMLPI. When converting - * parse tree to XML, we preserve a TOK_XMLSPACE node only if it's the sole - * child of a container tag. - */ -static JSParseNode * -XMLAtomNode(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - JSParseNode *pn; - JSToken *tp; - - pn = NewParseNode(cx, ts, PN_NULLARY, tc); - if (!pn) - return NULL; - tp = &CURRENT_TOKEN(ts); - pn->pn_op = tp->t_op; - pn->pn_atom = tp->t_atom; - if (tp->type == TOK_XMLPI) - pn->pn_atom2 = tp->t_atom2; - return pn; -} - -/* - * Parse the productions: - * - * XMLNameExpr: - * XMLName XMLNameExpr? - * { Expr } XMLNameExpr? - * - * Return a PN_LIST, PN_UNARY, or PN_NULLARY according as XMLNameExpr produces - * a list of names and/or expressions, a single expression, or a single name. - * If PN_LIST or PN_NULLARY, pn_type will be TOK_XMLNAME; if PN_UNARY, pn_type - * will be TOK_LC. - */ -static JSParseNode * -XMLNameExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - JSParseNode *pn, *pn2, *list; - JSTokenType tt; - - pn = list = NULL; - do { - tt = CURRENT_TOKEN(ts).type; - if (tt == TOK_LC) { - pn2 = XMLExpr(cx, ts, JS_TRUE, tc); - if (!pn2) - return NULL; - } else { - JS_ASSERT(tt == TOK_XMLNAME); - pn2 = XMLAtomNode(cx, ts, tc); - if (!pn2) - return NULL; - } - - if (!pn) { - pn = pn2; - } else { - if (!list) { - list = NewParseNode(cx, ts, PN_LIST, tc); - if (!list) - return NULL; - list->pn_type = TOK_XMLNAME; - list->pn_pos.begin = pn->pn_pos.begin; - PN_INIT_LIST_1(list, pn); - list->pn_extra = PNX_CANTFOLD; - pn = list; - } - pn->pn_pos.end = pn2->pn_pos.end; - PN_APPEND(pn, pn2); - } - } while ((tt = js_GetToken(cx, ts)) == TOK_XMLNAME || tt == TOK_LC); - - js_UngetToken(ts); - return pn; -} - -/* - * Macro to test whether an XMLNameExpr or XMLTagContent node can be folded - * at compile time into a JSXML tree. - */ -#define XML_FOLDABLE(pn) ((pn)->pn_arity == PN_LIST \ - ? ((pn)->pn_extra & PNX_CANTFOLD) == 0 \ - : (pn)->pn_type != TOK_LC) - -/* - * Parse the productions: - * - * XMLTagContent: - * XMLNameExpr - * XMLTagContent S XMLNameExpr S? = S? XMLAttr - * XMLTagContent S XMLNameExpr S? = S? { Expr } - * - * Return a PN_LIST, PN_UNARY, or PN_NULLARY according to how XMLTagContent - * produces a list of name and attribute values and/or braced expressions, a - * single expression, or a single name. - * - * If PN_LIST or PN_NULLARY, pn_type will be TOK_XMLNAME for the case where - * XMLTagContent: XMLNameExpr. If pn_type is not TOK_XMLNAME but pn_arity is - * PN_LIST, pn_type will be tagtype. If PN_UNARY, pn_type will be TOK_LC and - * we parsed exactly one expression. - */ -static JSParseNode * -XMLTagContent(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSTokenType tagtype, JSAtom **namep) -{ - JSParseNode *pn, *pn2, *list; - JSTokenType tt; - - pn = XMLNameExpr(cx, ts, tc); - if (!pn) - return NULL; - *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL; - list = NULL; - - while (js_MatchToken(cx, ts, TOK_XMLSPACE)) { - tt = js_GetToken(cx, ts); - if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_UngetToken(ts); - break; - } - - pn2 = XMLNameExpr(cx, ts, tc); - if (!pn2) - return NULL; - if (!list) { - list = NewParseNode(cx, ts, PN_LIST, tc); - if (!list) - return NULL; - list->pn_type = tagtype; - list->pn_pos.begin = pn->pn_pos.begin; - PN_INIT_LIST_1(list, pn); - pn = list; - } - PN_APPEND(pn, pn2); - if (!XML_FOLDABLE(pn2)) - pn->pn_extra |= PNX_CANTFOLD; - - js_MatchToken(cx, ts, TOK_XMLSPACE); - MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR); - js_MatchToken(cx, ts, TOK_XMLSPACE); - - tt = js_GetToken(cx, ts); - if (tt == TOK_XMLATTR) { - pn2 = XMLAtomNode(cx, ts, tc); - } else if (tt == TOK_LC) { - pn2 = XMLExpr(cx, ts, JS_TRUE, tc); - pn->pn_extra |= PNX_CANTFOLD; - } else { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_XML_ATTR_VALUE); - return NULL; - } - if (!pn2) - return NULL; - pn->pn_pos.end = pn2->pn_pos.end; - PN_APPEND(pn, pn2); - } - - return pn; -} - -#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ - JS_BEGIN_MACRO \ - if ((tt) <= TOK_EOF) { \ - if ((tt) == TOK_EOF) { \ - js_ReportCompileErrorNumber(cx, ts, \ - JSREPORT_TS | JSREPORT_ERROR, \ - JSMSG_END_OF_XML_SOURCE); \ - } \ - return result; \ - } \ - JS_END_MACRO - -static JSParseNode * -XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowList); - -/* - * Consume XML element tag content, including the TOK_XMLETAGO (flags &= ~TSF_XMLTAGMODE; - for (;;) { - ts->flags |= TSF_XMLTEXTMODE; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_XMLTEXTMODE; - XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); - - JS_ASSERT(tt == TOK_XMLSPACE || tt == TOK_XMLTEXT); - textAtom = CURRENT_TOKEN(ts).t_atom; - if (textAtom) { - /* Non-zero-length XML text scanned. */ - pn2 = XMLAtomNode(cx, ts, tc); - if (!pn2) - return JS_FALSE; - pn->pn_pos.end = pn2->pn_pos.end; - PN_APPEND(pn, pn2); - } - - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); - if (tt == TOK_XMLETAGO) - break; - - if (tt == TOK_LC) { - pn2 = XMLExpr(cx, ts, JS_FALSE, tc); - pn->pn_extra |= PNX_CANTFOLD; - } else if (tt == TOK_XMLSTAGO) { - pn2 = XMLElementOrList(cx, ts, tc, JS_FALSE); - if (pn2) { - pn2->pn_extra &= ~PNX_XMLROOT; - pn->pn_extra |= pn2->pn_extra; - } - } else { - JS_ASSERT(tt == TOK_XMLCDATA || tt == TOK_XMLCOMMENT || - tt == TOK_XMLPI); - pn2 = XMLAtomNode(cx, ts, tc); - } - if (!pn2) - return JS_FALSE; - pn->pn_pos.end = pn2->pn_pos.end; - PN_APPEND(pn, pn2); - } - - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_XMLETAGO); - ts->flags |= TSF_XMLTAGMODE; - return JS_TRUE; -} - -/* - * Return a PN_LIST node containing an XML or XMLList Initialiser. - */ -static JSParseNode * -XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowList) -{ - JSParseNode *pn, *pn2, *list; - JSBool hadSpace; - JSTokenType tt; - JSAtom *startAtom, *endAtom; - - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_XMLSTAGO); - pn = NewParseNode(cx, ts, PN_LIST, tc); - if (!pn) - return NULL; - - ts->flags |= TSF_XMLTAGMODE; - hadSpace = js_MatchToken(cx, ts, TOK_XMLSPACE); - tt = js_GetToken(cx, ts); - if (tt == TOK_ERROR) - return NULL; - - if (tt == TOK_XMLNAME || tt == TOK_LC) { - /* - * XMLElement. Append the tag and its contents, if any, to pn. - */ - pn2 = XMLTagContent(cx, ts, tc, TOK_XMLSTAGO, &startAtom); - if (!pn2) - return NULL; - js_MatchToken(cx, ts, TOK_XMLSPACE); - - tt = js_GetToken(cx, ts); - if (tt == TOK_XMLPTAGC) { - /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ - if (pn2->pn_type == TOK_XMLSTAGO) { - PN_INIT_LIST(pn); - RecycleTree(pn, tc); - pn = pn2; - } else { - JS_ASSERT(pn2->pn_type == TOK_XMLNAME || - pn2->pn_type == TOK_LC); - PN_INIT_LIST_1(pn, pn2); - if (!XML_FOLDABLE(pn2)) - pn->pn_extra |= PNX_CANTFOLD; - } - pn->pn_type = TOK_XMLPTAGC; - pn->pn_extra |= PNX_XMLROOT; - } else { - /* We had better have a tag-close (>) at this point. */ - if (tt != TOK_XMLTAGC) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); - return NULL; - } - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; - - /* Make sure pn2 is a TOK_XMLSTAGO list containing tag contents. */ - if (pn2->pn_type != TOK_XMLSTAGO) { - PN_INIT_LIST_1(pn, pn2); - if (!XML_FOLDABLE(pn2)) - pn->pn_extra |= PNX_CANTFOLD; - pn2 = pn; - pn = NewParseNode(cx, ts, PN_LIST, tc); - if (!pn) - return NULL; - } - - /* Now make pn a nominal-root TOK_XMLELEM list containing pn2. */ - pn->pn_type = TOK_XMLELEM; - PN_INIT_LIST_1(pn, pn2); - if (!XML_FOLDABLE(pn2)) - pn->pn_extra |= PNX_CANTFOLD; - pn->pn_extra |= PNX_XMLROOT; - - /* Get element contents and delimiting end-tag-open sequence. */ - if (!XMLElementContent(cx, ts, pn, tc)) - return NULL; - - js_MatchToken(cx, ts, TOK_XMLSPACE); - tt = js_GetToken(cx, ts); - XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL); - if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); - return NULL; - } - - /* Parse end tag; check mismatch at compile-time if we can. */ - pn2 = XMLTagContent(cx, ts, tc, TOK_XMLETAGO, &endAtom); - if (!pn2) - return NULL; - if (pn2->pn_type == TOK_XMLETAGO) { - /* Oops, end tag has attributes! */ - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); - return NULL; - } - if (endAtom && startAtom && endAtom != startAtom) { - /* End vs. start tag name mismatch: point to the tag name. */ - ++pn2->pn_pos.begin.index; - js_ReportCompileErrorNumber(cx, pn2, - JSREPORT_PN | JSREPORT_ERROR, - JSMSG_XML_TAG_NAME_MISMATCH); - return NULL; - } - - /* Make a TOK_XMLETAGO list with pn2 as its single child. */ - JS_ASSERT(pn2->pn_type == TOK_XMLNAME || pn2->pn_type == TOK_LC); - list = NewParseNode(cx, ts, PN_LIST, tc); - if (!list) - return NULL; - list->pn_type = TOK_XMLETAGO; - PN_INIT_LIST_1(list, pn2); - PN_APPEND(pn, list); - if (!XML_FOLDABLE(pn2)) { - list->pn_extra |= PNX_CANTFOLD; - pn->pn_extra |= PNX_CANTFOLD; - } - - js_MatchToken(cx, ts, TOK_XMLSPACE); - MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX); - } - - /* Set pn_op now that pn has been updated to its final value. */ - pn->pn_op = JSOP_TOXML; - } else if (!hadSpace && allowList && tt == TOK_XMLTAGC) { - /* XMLList Initialiser. */ - pn->pn_type = TOK_XMLLIST; - pn->pn_op = JSOP_TOXMLLIST; - PN_INIT_LIST(pn); - pn->pn_extra |= PNX_XMLROOT; - if (!XMLElementContent(cx, ts, pn, tc)) - return NULL; - - MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX); - } else { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_XML_NAME_SYNTAX); - return NULL; - } - - pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; - ts->flags &= ~TSF_XMLTAGMODE; - return pn; -} - -static JSParseNode * -XMLElementOrListRoot(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowList) -{ - uint32 oldopts; - JSParseNode *pn; - - /* - * Force XML support to be enabled so that comments and CDATA literals - * are recognized, instead of ). - */ - oldopts = JS_SetOptions(cx, cx->options | JSOPTION_XML); - pn = XMLElementOrList(cx, ts, tc, allowList); - JS_SetOptions(cx, oldopts); - return pn; -} - -JS_FRIEND_API(JSParseNode *) -js_ParseXMLTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts, - JSBool allowList) -{ - JSStackFrame *fp, frame; - JSParseNode *pn; - JSTreeContext tc; - JSTokenType tt; - - /* - * 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; - if (fp) { - frame.flags = fp->flags & (JSFRAME_SPECIAL | JSFRAME_COMPILE_N_GO | - JSFRAME_SCRIPT_OBJECT); - } - cx->fp = &frame; - } - - JS_KEEP_ATOMS(cx->runtime); - TREE_CONTEXT_INIT(&tc); - - /* Set XML-only mode to turn off special treatment of {expr} in XML. */ - ts->flags |= TSF_OPERAND | TSF_XMLONLYMODE; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - - if (tt != TOK_XMLSTAGO) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); - pn = NULL; - } else { - pn = XMLElementOrListRoot(cx, ts, &tc, allowList); - } - - ts->flags &= ~TSF_XMLONLYMODE; - TREE_CONTEXT_FINISH(&tc); - JS_UNKEEP_ATOMS(cx->runtime); - cx->fp = fp; - return pn; -} - -#endif /* JS_HAS_XMLSUPPORT */ - -static JSParseNode * -PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) -{ - JSTokenType tt; - JSParseNode *pn, *pn2, *pn3; -#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 tt switch case - * should set notsharp. - */ -#endif - - CHECK_RECURSION(); - - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - -#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 || JS_HAS_XML_SUPPORT - case TOK_FUNCTION: -#if JS_HAS_XML_SUPPORT - if (js_MatchToken(cx, ts, TOK_DBLCOLON)) { - pn2 = NewParseNode(cx, ts, PN_NULLARY, tc); - if (!pn2) - return NULL; - pn2->pn_type = TOK_FUNCTION; - pn = QualifiedSuffix(cx, ts, pn2, tc); - if (!pn) - return NULL; - break; - } -#endif - 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, ts, PN_LIST, tc); - if (!pn) - return NULL; - pn->pn_type = TOK_RB; - -#if JS_HAS_SHARP_VARS - if (defsharp) { - PN_INIT_LIST_1(pn, defsharp); - defsharp = NULL; - } else -#endif - PN_INIT_LIST(pn); - - ts->flags |= TSF_OPERAND; - matched = js_MatchToken(cx, ts, TOK_RB); - ts->flags &= ~TSF_OPERAND; - if (!matched) { - for (atomIndex = 0; ; atomIndex++) { - if (atomIndex == ATOM_INDEX_LIMIT) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_ARRAY_INIT_TOO_BIG); - return NULL; - } - - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; - if (tt == TOK_RB) { - pn->pn_extra |= PNX_ENDCOMMA; - break; - } - - if (tt == TOK_COMMA) { - /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ - js_MatchToken(cx, ts, TOK_COMMA); - pn2 = NewParseNode(cx, 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, 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, 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, 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, ts, PN_NULLARY, tc); - if (pn3) - pn3->pn_atom = CURRENT_TOKEN(ts).t_atom; - break; - case TOK_RC: - if (!js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_TRAILING_COMMA)) { - return NULL; - } - goto end_obj_init; - default: - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | 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, - JSREPORT_TS | 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, 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, 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: - pn = NewParseNode(cx, ts, PN_UNARY, tc); - if (!pn) - return NULL; - pn2 = BracketedExpr(cx, ts, tc); - 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; - -#if JS_HAS_XML_SUPPORT - case TOK_STAR: - pn = QualifiedIdentifier(cx, ts, tc); - if (!pn) - return NULL; - notsharp = JS_TRUE; - break; - - case TOK_AT: - pn = AttributeIdentifier(cx, ts, tc); - if (!pn) - return NULL; - notsharp = JS_TRUE; - break; - - case TOK_XMLSTAGO: - pn = XMLElementOrListRoot(cx, ts, tc, JS_TRUE); - if (!pn) - return NULL; - notsharp = JS_TRUE; /* XXXbe could be sharp? */ - break; -#endif /* JS_HAS_XML_SUPPORT */ - - case TOK_STRING: -#if JS_HAS_SHARP_VARS - notsharp = JS_TRUE; - /* FALL THROUGH */ -#endif - -#if JS_HAS_XML_SUPPORT - case TOK_XMLCDATA: - case TOK_XMLCOMMENT: - case TOK_XMLPI: -#endif - case TOK_NAME: - case TOK_OBJECT: - pn = NewParseNode(cx, ts, PN_NULLARY, tc); - if (!pn) - return NULL; - pn->pn_atom = CURRENT_TOKEN(ts).t_atom; -#if JS_HAS_XML_SUPPORT - if (tt == TOK_XMLPI) - pn->pn_atom2 = CURRENT_TOKEN(ts).t_atom2; - else -#endif - pn->pn_op = CURRENT_TOKEN(ts).t_op; - if (tt == TOK_NAME) { - pn->pn_arity = PN_NAME; - pn->pn_expr = NULL; - pn->pn_slot = -1; - pn->pn_attrs = 0; - -#if JS_HAS_XML_SUPPORT - if (js_MatchToken(cx, ts, TOK_DBLCOLON)) { - pn = QualifiedSuffix(cx, ts, pn, tc); - if (!pn) - return NULL; - break; - } -#endif - - /* 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; - } else { - JSAtomListElement *ale; - JSStackFrame *fp; - JSStmtInfo *stmt; - - /* Measure optimizable global variable uses. */ - ATOM_LIST_SEARCH(ale, &tc->decls, pn->pn_atom); - if (ale && - !(fp = cx->fp)->fun && - fp->scopeChain == fp->varobj && - !js_InWithStatement(tc) && - !js_InCatchBlock(tc, pn->pn_atom)) { - tc->globalUses++; - for (stmt = tc->topStmt; stmt; stmt = stmt->down) { - if (STMT_IS_LOOP(stmt)) { - tc->loopyGlobalUses++; - break; - } - } - } - } - } - break; - - case TOK_NUMBER: - pn = NewParseNode(cx, 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, 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_ERROR: - /* The scanner or one of its subroutines reported the error. */ - return NULL; - - default: - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); - return NULL; - } - -#if JS_HAS_SHARP_VARS - if (defsharp) { - if (notsharp) { - badsharp: - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | 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; -} - -#if JS_HAS_XML_SUPPORT - -static JSBool -FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) -{ - JSTokenType tt; - JSParseNode **pnp, *pn1, *pn2; - JSString *accum, *str; - uint32 i, j; - - JS_ASSERT(pn->pn_arity == PN_LIST); - tt = pn->pn_type; - pnp = &pn->pn_head; - pn1 = *pnp; - accum = NULL; - if ((pn->pn_extra & PNX_CANTFOLD) == 0) { - if (tt == TOK_XMLETAGO) - accum = ATOM_TO_STRING(cx->runtime->atomState.etagoAtom); - else if (tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) - accum = ATOM_TO_STRING(cx->runtime->atomState.stagoAtom); - } - - for (pn2 = pn1, i = j = 0; pn2; pn2 = pn2->pn_next, i++) { - /* The parser already rejected end-tags with attributes. */ - JS_ASSERT(tt != TOK_XMLETAGO || i == 0); - switch (pn2->pn_type) { - case TOK_XMLATTR: - if (!accum) - goto cantfold; - /* FALL THROUGH */ - case TOK_XMLNAME: - case TOK_XMLSPACE: - case TOK_XMLTEXT: - case TOK_STRING: - if (pn2->pn_arity == PN_LIST) - goto cantfold; - str = ATOM_TO_STRING(pn2->pn_atom); - break; - - case TOK_XMLCDATA: - str = js_MakeXMLCDATAString(cx, ATOM_TO_STRING(pn2->pn_atom)); - if (!str) - return JS_FALSE; - break; - - case TOK_XMLCOMMENT: - str = js_MakeXMLCommentString(cx, ATOM_TO_STRING(pn2->pn_atom)); - if (!str) - return JS_FALSE; - break; - - case TOK_XMLPI: - str = js_MakeXMLPIString(cx, ATOM_TO_STRING(pn2->pn_atom), - ATOM_TO_STRING(pn2->pn_atom2)); - if (!str) - return JS_FALSE; - break; - - cantfold: - default: - JS_ASSERT(*pnp == pn1); - if ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && - (i & 1) ^ (j & 1)) { -#ifdef DEBUG_brendanXXX - printf("1: %d, %d => %s\n", - i, j, accum ? JS_GetStringBytes(accum) : "NULL"); -#endif - } else if (accum && pn1 != pn2) { - while (pn1->pn_next != pn2) { - pn1 = RecycleTree(pn1, tc); - --pn->pn_count; - } - pn1->pn_type = TOK_XMLTEXT; - pn1->pn_op = JSOP_STRING; - pn1->pn_arity = PN_NULLARY; - pn1->pn_atom = js_AtomizeString(cx, accum, 0); - if (!pn1->pn_atom) - return JS_FALSE; - JS_ASSERT(pnp != &pn1->pn_next); - *pnp = pn1; - } - pnp = &pn2->pn_next; - pn1 = *pnp; - accum = NULL; - continue; - } - - if (accum) { - str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) - ? js_AddAttributePart(cx, i & 1, accum, str) - : js_ConcatStrings(cx, accum, str); - if (!str) - return JS_FALSE; -#ifdef DEBUG_brendanXXX - printf("2: %d, %d => %s (%u)\n", - i, j, JS_GetStringBytes(str), JSSTRING_LENGTH(str)); -#endif - ++j; - } - accum = str; - } - - if (accum) { - str = NULL; - if ((pn->pn_extra & PNX_CANTFOLD) == 0) { - if (tt == TOK_XMLPTAGC) - str = ATOM_TO_STRING(cx->runtime->atomState.ptagcAtom); - else if (tt == TOK_XMLSTAGO || tt == TOK_XMLETAGO) - str = ATOM_TO_STRING(cx->runtime->atomState.tagcAtom); - } - if (str) { - accum = js_ConcatStrings(cx, accum, str); - if (!accum) - return JS_FALSE; - } - - JS_ASSERT(*pnp == pn1); - while (pn1->pn_next) { - pn1 = RecycleTree(pn1, tc); - --pn->pn_count; - } - pn1->pn_type = TOK_XMLTEXT; - pn1->pn_op = JSOP_STRING; - pn1->pn_arity = PN_NULLARY; - pn1->pn_atom = js_AtomizeString(cx, accum, 0); - if (!pn1->pn_atom) - return JS_FALSE; - JS_ASSERT(pnp != &pn1->pn_next); - *pnp = pn1; - } - - if (pn1 && pn->pn_count == 1) { - /* - * Only one node under pn, and it has been folded: move pn1 onto pn - * unless pn is an XML root (in which case we need it to tell the code - * generator to emit a JSOP_TOXML or JSOP_TOXMLLIST op). If pn is an - * XML root *and* it's a point-tag, rewrite it to TOK_XMLELEM to avoid - * extra "<" and "/>" bracketing at runtime. - */ - if (!(pn->pn_extra & PNX_XMLROOT)) { - PN_MOVE_NODE(pn, pn1); - } else if (tt == TOK_XMLPTAGC) { - pn->pn_type = TOK_XMLELEM; - pn->pn_op = JSOP_TOXML; - } - } - return JS_TRUE; -} - -#endif /* JS_HAS_XML_SUPPORT */ - -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: - { - uint16 oldflags = tc->flags; - - tc->flags = (uint16) pn->pn_flags; - if (!js_FoldConstants(cx, pn->pn_body, tc)) - return JS_FALSE; - tc->flags = oldflags; - break; - } - - case PN_LIST: -#if 0 /* JS_HAS_XML_SUPPORT */ - switch (pn->pn_type) { - case TOK_XMLELEM: - case TOK_XMLLIST: - case TOK_XMLPTAGC: - /* - * Try to fold this XML parse tree once, from the top down, into - * a JSXML tree with just one object wrapping the tree root. - * - * Certain subtrees could be folded similarly, but we'd have to - * ensure that none used namespace prefixes declared elsewhere in - * its super-tree, and we would have to convert each XML object - * created at runtime for such sub-trees back into a string, and - * concatenate and re-parse anyway. - */ - if ((pn->pn_extra & (PNX_XMLROOT | PNX_CANTFOLD)) == PNX_XMLROOT && - !(tc->flags & TCF_HAS_DEFXMLNS)) { - JSObject *obj; - JSAtom *atom; - - obj = js_ParseNodeToXMLObject(cx, pn); - if (!obj) - return JS_FALSE; - atom = js_AtomizeObject(cx, obj, 0); - if (!atom) - return JS_FALSE; - pn->pn_op = JSOP_XMLOBJECT; - pn->pn_arity = PN_NULLARY; - pn->pn_atom = atom; - return JS_TRUE; - } - - /* - * Can't fold from parse node to XML tree -- try folding strings - * as much as possible, and folding XML sub-trees bottom up to - * minimize string concatenation and ToXML/ToXMLList operations - * at runtime. - */ - break; - - default:; - } -#endif - - /* 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 = RecycleTree(pn2, tc)) { - str2 = ATOM_TO_STRING(pn2->pn_atom); - length2 = str2->length; - js_strncpy(chars, str2->chars, length2); - chars += length2; - } - *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; - -#if JS_HAS_XML_SUPPORT - case TOK_XMLELEM: - case TOK_XMLLIST: - case TOK_XMLPTAGC: - case TOK_XMLSTAGO: - case TOK_XMLETAGO: - case TOK_XMLNAME: - if (pn->pn_arity == PN_LIST) { - JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0); - if (!FoldXMLConstants(cx, pn, tc)) - return JS_FALSE; - } - break; - - case TOK_AT: - if (pn1->pn_type == TOK_XMLNAME) { - jsval v; - JSAtom *atom; - - v = ATOM_KEY(pn1->pn_atom); - if (!js_ToAttributeName(cx, &v)) - return JS_FALSE; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); - atom = js_AtomizeObject(cx, JSVAL_TO_OBJECT(v), 0); - if (!atom) - return JS_FALSE; - - pn->pn_type = TOK_XMLNAME; - pn->pn_op = JSOP_OBJECT; - pn->pn_arity = PN_NULLARY; - pn->pn_atom = atom; - RecycleTree(pn1, tc); - } - break; -#endif /* JS_HAS_XML_SUPPORT */ - - default:; - } - - return JS_TRUE; -} diff --git a/src/dom/js/jsparse.h b/src/dom/js/jsparse.h deleted file mode 100644 index 24b27bdc1..000000000 --- a/src/dom/js/jsparse.h +++ /dev/null @@ -1,414 +0,0 @@ -/* -*- 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 "jsconfig.h" -#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 - * > so that code generation can emit a left-associative branch - * around when A is false). Nodes are labeled by token type, with a - * JSOp secondary label when needed: - * - * Label Variant Members - * ----- ------- ------- - * - * 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 - * - * - * 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 - * pn_val: constant value if lookup or table switch - * 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' - * if TOK_VAR, its pn_extra may have PNX_POPVAR - * and PNX_FORINVAR bits set - * 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 - * - * - * 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 ), 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 . - * TOK_DBLDOT 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: PN_ENDCOMMA 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, or - * JSOP_REGEXP - * 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 - * TOK_ANYNAME nullary pn_op: JSOP_ANYNAME - * pn_atom: cx->runtime->atomState.starAtom - * TOK_AT unary pn_op: JSOP_TOATTRNAME; pn_kid attribute id/expr - * TOK_DBLCOLON binary pn_op: JSOP_QNAME - * pn_left: TOK_ANYNAME or TOK_NAME node - * pn_right: TOK_STRING "*" node, or expr within [] - * name pn_op: JSOP_QNAMECONST - * pn_expr: TOK_ANYNAME or TOK_NAME left operand - * pn_atom: name on right of :: - * TOK_XMLELEM list XML element node - * pn_head: start tag, content1, ... contentN, end tag - * pn_count: 2 + N where N is number of content nodes - * N may be > x.length() if {expr} embedded - * TOK_XMLLIST list XML list node - * pn_head: content1, ... contentN - * TOK_XMLSTAGO, list XML start, end, and point tag contents - * TOK_XMLETAGC, pn_head: tag name or {expr}, ... XML attrs ... - * TOK_XMLPTAGO - * TOK_XMLNAME nullary pn_atom: XML name, with no {expr} embedded - * TOK_XMLNAME list pn_head: tag name or {expr}, ... name or {expr} - * TOK_XMLATTR, nullary pn_atom: attribute value string; pn_op: JSOP_STRING - * TOK_XMLCDATA, - * TOK_XMLCOMMENT - * TOK_XMLPI nullary pn_atom: XML processing instruction target - * pn_atom2: XML PI content, or null if no content - * TOK_XMLTEXT nullary pn_atom: marked-up text, or null if empty string - * TOK_LC unary {expr} in XML tag or content; pn_kid is expr - * - * So an XML tag with no {expr} and three attributes is a list with the form: - * - * (tagname attrname1 attrvalue1 attrname2 attrvalue2 attrname2 attrvalue3) - * - * An XML tag with embedded expressions like so: - * - * - * - * would have the form: - * - * ((name1 {expr1}) (name2 {expr2} name3) {expr3}) - * - * where () bracket a list with elements separated by spaces, and {expr} is a - * TOK_LC unary node with expr as its kid. - * - * Thus, the attribute name/value pairs occupy successive odd and even list - * locations, where pn_head is the TOK_XMLNAME node at list location 0. The - * parser builds the same sort of structures for elements: - * - * Hi there!How are you?{x + y} - * - * translates to: - * - * ((a x {x}) 'Hi there!' ((b y {y}) 'How are you?') ((answer) {x + y})) - */ -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 { - uint16 pn_type; - uint8 pn_op; - int8 pn_arity; - JSTokenPos pn_pos; - ptrdiff_t pn_offset; /* first generated bytecode offset */ - 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; - struct { - JSAtom *atom; /* first atom in pair */ - JSAtom *atom2; /* second atom in pair or null */ - } apair; - jsdouble dval; /* aligned numeric literal value */ - } pn_u; - JSParseNode *pn_next; /* to align dval and pn_u on RISCs */ -#if JS_HAS_XML_SUPPORT - JSTokenStream *pn_ts; /* token stream for XML error reports */ -#endif -}; - -#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 -#define pn_atom2 pn_u.apair.atom2 - -/* PN_LIST pn_extra flags. */ -#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */ -#define PNX_CANTFOLD 0x02 /* TOK_PLUS list has unfoldable term */ -#define PNX_POPVAR 0x04 /* TOK_VAR last result needs popping */ -#define PNX_FORINVAR 0x08 /* TOK_VAR is left kid of TOK_IN node, - which is left kid of TOK_FOR */ -#define PNX_ENDCOMMA 0x10 /* array literal has comma at end */ -#define PNX_XMLROOT 0x20 /* top-most node in XML literal tree */ - -/* - * 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 = (list)->pn_extra = 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; \ - (list)->pn_extra = 0; \ - 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); - -#if JS_HAS_XML_SUPPORT -JS_FRIEND_API(JSParseNode *) -js_ParseXMLTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts, - JSBool allowList); -#endif - -JS_END_EXTERN_C - -#endif /* jsparse_h___ */ diff --git a/src/dom/js/jsprf.c b/src/dom/js/jsprf.c deleted file mode 100644 index ba7c0f03b..000000000 --- a/src/dom/js/jsprf.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include "jsprf.h" -#include "jslong.h" -#include "jsutil.h" /* Added by JSIFY */ -#include "jspubtd.h" -#include "jsstr.h" - -/* -** 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_WSTRING 11 -#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(", &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); -} - -static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, - int flags) -{ - int result; - /* - * Supply NULL as the JSContext; errors are not reported, - * and malloc() is used to allocate the buffer buffer. - */ - if (ws) { - int slen = js_strlen(ws); - char *s = js_DeflateString(NULL, ws, slen); - if (!s) - return -1; /* JSStuffFunc error indicator. */ - result = cvt_s(ss, s, width, prec, flags); - free(s); - } else { - result = cvt_s(ss, NULL, width, prec, flags); - } - return result; -} - -/* -** BuildArgArray 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 improve 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 = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : 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 ) - free( 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_WSTRING: (void)va_arg( ap, jschar* ); break; - - case TYPE_INTSTR: (void)va_arg( ap, JSIntn* ); break; - - case TYPE_DOUBLE: (void)va_arg( ap, double ); break; - - default: - if( nas != nasArray ) - free( 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; - jschar wch; - int i; - long l; - JSInt64 ll; - double d; - const char *s; - const jschar* ws; - 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 . */ -#ifdef JS_C_STRINGS_ARE_UTF8 - char utf8buf[6]; - int utf8len; -#endif - - /* - ** 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 ) ) - free( 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': - if ((flags & FLAG_LEFT) == 0) { - while (width-- > 1) { - rv = (*ss->stuff)(ss, " ", 1); - if (rv < 0) { - return rv; - } - } - } - switch (type) { - case TYPE_INT16: - /* Treat %hc as %c if JS_C_STRINGS_ARE_UTF8 is undefined. */ -#ifdef JS_C_STRINGS_ARE_UTF8 - u.wch = va_arg(ap, int); - utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch); - rv = (*ss->stuff)(ss, utf8buf, utf8len); - break; -#endif - case TYPE_INTN: - u.ch = va_arg(ap, int); - rv = (*ss->stuff)(ss, &u.ch, 1); - break; - } - 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': - if(type == TYPE_INT16) { - /* - * This would do a simple string/byte conversion - * if JS_C_STRINGS_ARE_UTF8 is not defined. - */ - u.ws = va_arg(ap, const jschar*); - rv = cvt_ws(ss, u.ws, width, prec, flags); - } else { - 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 ) ){ - free( 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) -{ - free(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) { - free(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[-1] = '\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) { - free(ss.base); - } - return 0; - } - return ss.base; -} - diff --git a/src/dom/js/jsprf.h b/src/dom/js/jsprf.h deleted file mode 100644 index 0eb910f27..000000000 --- a/src/dom/js/jsprf.h +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- 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 -** %hs - 16-bit version of above (only available if compiled with JS_C_STRINGS_ARE_UTF8) -** %c - character -** %hc - 16-bit version of above (only available if compiled with JS_C_STRINGS_ARE_UTF8) -** %p - pointer (deals with machine dependent pointer size) -** %f - float -** %g - float -*/ -#include "jstypes.h" -#include -#include - -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 deleted file mode 100644 index ed12f1bde..000000000 --- a/src/dom/js/jsprvtd.h +++ /dev/null @@ -1,203 +0,0 @@ -/* -*- 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" - -/* Internal identifier (jsid) macros. */ -#define JSID_ATOM 0x0 -#define JSID_INT 0x1 -#define JSID_OBJECT 0x2 -#define JSID_TAGMASK 0x3 -#define JSID_TAG(id) ((id) & JSID_TAGMASK) -#define JSID_SETTAG(id,t) ((id) | (t)) -#define JSID_CLRTAG(id) ((id) & ~(jsid)JSID_TAGMASK) - -#define JSID_IS_ATOM(id) (JSID_TAG(id) == JSID_ATOM) -#define JSID_TO_ATOM(id) ((JSAtom *)(id)) -#define ATOM_TO_JSID(atom) ((jsid)(atom)) -#define ATOM_JSID_TO_JSVAL(id) ATOM_KEY(JSID_TO_ATOM(id)) - -#define JSID_IS_INT(id) ((id) & JSID_INT) -#define JSID_TO_INT(id) ((jsint)(id) >> 1) -#define INT_TO_JSID(i) (((jsint)(i) << 1) | JSID_INT) -#define INT_JSID_TO_JSVAL(id) (id) -#define INT_JSVAL_TO_JSID(v) (v) - -#define JSID_IS_OBJECT(id) (JSID_TAG(id) == JSID_OBJECT) -#define JSID_TO_OBJECT(id) ((JSObject *) JSID_CLRTAG(id)) -#define OBJECT_TO_JSID(obj) ((jsid)(obj) | JSID_OBJECT) -#define OBJECT_JSID_TO_JSVAL(id) OBJECT_TO_JSVAL(JSID_CLRTAG(id)) -#define OBJECT_JSVAL_TO_JSID(v) OBJECT_TO_JSID(JSVAL_TO_OBJECT(v)) - -/* 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 JSStringBuffer JSStringBuffer; -typedef struct JSSubString JSSubString; -typedef struct JSXML JSXML; -typedef struct JSXMLNamespace JSXMLNamespace; -typedef struct JSXMLQName JSXMLQName; -typedef struct JSXMLArray JSXMLArray; -typedef struct JSXMLArrayCursor JSXMLArrayCursor; - -/* "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, /* first line */ - 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 *not* to - * 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 deleted file mode 100644 index e9da92783..000000000 --- a/src/dom/js/jspubtd.h +++ /dev/null @@ -1,618 +0,0 @@ -/* -*- 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_1_6 = 160, - 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_NULL, /* null */ - JSTYPE_XML, /* xml object */ - 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 JSExtendedClass JSExtendedClass; -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 JSXMLObjectOps JSXMLObjectOps; -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 - * JSRESOLVE_DETECTING 'if (o.p)...' or similar detection opcode sequence - * JSRESOLVE_DECLARING var, const, or function prolog declaration opcode - * JSRESOLVE_CLASSNAME class name used when constructing - * - * 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, and to - * finalize the object. - * - * 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. - * - * Further extension to preserve API compatibility: if this function returns - * a pointer to JSXMLObjectOps.base, not to JSObjectOps, then the engine calls - * extended hooks needed for E4X. - */ -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); - -/* - * The optional JSClass.reserveSlots hook allows a class to make computed - * per-instance object slots reservations, in addition to or instead of using - * JSCLASS_HAS_RESERVED_SLOTS(n) in the JSClass.flags initializer to reserve - * a constant-per-class number of slots. Implementations of this hook should - * return the number of slots to reserve, not including any reserved by using - * JSCLASS_HAS_RESERVED_SLOTS(n) in JSClass.flags. - * - * NB: called with obj locked by the JSObjectOps-specific mutual exclusion - * mechanism appropriate for obj, so don't nest other operations that might - * also lock obj. - */ -typedef uint32 -(* JS_DLL_CALLBACK JSReserveSlotsOp)(JSContext *cx, JSObject *obj); - -/* 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); - -/* - * 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 JSBool -(* JS_DLL_CALLBACK JSSetRequiredSlotOp)(JSContext *cx, JSObject *obj, - uint32 slot, jsval v); - -typedef JSObject * -(* JS_DLL_CALLBACK JSGetMethodOp)(JSContext *cx, JSObject *obj, jsid id, - jsval *vp); - -typedef JSBool -(* JS_DLL_CALLBACK JSSetMethodOp)(JSContext *cx, JSObject *obj, jsid id, - jsval *vp); - -typedef JSBool -(* JS_DLL_CALLBACK JSEnumerateValuesOp)(JSContext *cx, JSObject *obj, - JSIterateOp enum_op, - jsval *statep, jsid *idp, jsval *vp); - -typedef JSBool -(* JS_DLL_CALLBACK JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, - JSBool *bp); - -typedef JSBool -(* JS_DLL_CALLBACK JSConcatenateOp)(JSContext *cx, JSObject *obj, jsval v, - jsval *vp); - -/* 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 { - /* The error format string (UTF-8 if JS_C_STRINGS_ARE_UTF8 is defined). */ - const char *format; - - /* The number of arguments to expand in the formatted error message. */ - uint16 argCount; - - /* One of the JSExnType constants above. */ - int16 exnType; -} 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); - -typedef JSBool -(* JS_DLL_CALLBACK JSLocaleToUnicode)(JSContext *cx, char *src, 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 deleted file mode 100644 index e9400eb09..000000000 --- a/src/dom/js/jsregexp.c +++ /dev/null @@ -1,4180 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set sw=4 ts=8 et tw=80: - * - * ***** 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 -#include -#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" - -#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) ((unsigned)((op) - REOP_SIMPLE_START) < \ - (unsigned)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 */ - size_t parenIndex; /* or a parenthesis index */ - struct { /* or a quantifier range */ - uintN min; - uintN max; - JSPackedBool greedy; - } range; - struct { /* or a character class */ - size_t startIndex; - size_t kidlen; /* length of string at kid, in jschars */ - size_t index; /* index into class list */ - uint16 bmsize; /* bitmap size, based on max char code */ - JSPackedBool sense; - } ucclass; - struct { /* or a literal sequence */ - jschar chr; /* of one character */ - size_t 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; - size_t parenCount; - size_t classCount; /* number of [] encountered */ - size_t treeDepth; /* maximum depth of parse tree */ - size_t progLength; /* estimated bytecode length */ - RENode *result; - size_t classBitmapsMem; /* memory to hold all class bitmaps */ - struct { - const jschar *start; /* small cache of class strings */ - size_t length; /* since they're often the same */ - size_t index; - } classCache[CLASS_CACHE_SIZE]; - uint16 flags; -} CompilerState; - -typedef struct EmitStateStackEntry { - jsbytecode *altHead; /* start of REOP_ALT* opcode */ - jsbytecode *nextAltFixup; /* fixup pointer to next-alt offset */ - jsbytecode *nextTermFixup; /* fixup ptr. to REOP_JUMP offset */ - jsbytecode *endTermFixup; /* fixup ptr. to REOPT_ALTPREREQ* offset */ - RENode *continueNode; /* original REOP_ALT* node being stacked */ - jsbytecode continueOp; /* REOP_JUMP or REOP_ENDALT continuation */ - JSPackedBool jumpToJumpFlag; /* true if we've patched jump-to-jump to - avoid 16-bit unsigned offset overflow */ -} EmitStateStackEntry; - -/* - * Immediate operand sizes and getter/setters. Unlike the ones in jsopcode.h, - * the getters and setters take the pc of the offset, not of the opcode before - * the offset. - */ -#define ARG_LEN 2 -#define GET_ARG(pc) ((uint16)(((pc)[0] << 8) | (pc)[1])) -#define SET_ARG(pc, arg) ((pc)[0] = (jsbytecode) ((arg) >> 8), \ - (pc)[1] = (jsbytecode) (arg)) - -#define OFFSET_LEN ARG_LEN -#define OFFSET_MAX (JS_BIT(ARG_LEN * 8) - 1) -#define GET_OFFSET(pc) GET_ARG(pc) - -/* - * Maximum supported tree depth is maximum size of EmitStateStackEntry stack. - * For sanity, we limit it to 2^24 bytes. - */ -#define TREE_DEPTH_MAX (JS_BIT(24) / sizeof(EmitStateStackEntry)) - -/* - * The maximum memory that can be allocated for class bitmaps. - * For sanity, we limit it to 2^24 bytes. - */ -#define CLASS_BITMAPS_MEM_LIMIT JS_BIT(24) - -/* - * Functions to get size and write/read bytecode that represent small indexes - * compactly. - * Each byte in the code represent 7-bit chunk of the index. 8th bit when set - * indicates that the following byte brings more bits to the index. Otherwise - * this is the last byte in the index bytecode representing highest index bits. - */ -static size_t -GetCompactIndexWidth(size_t index) -{ - size_t width; - - for (width = 1; (index >>= 7) != 0; ++width) { } - return width; -} - -static jsbytecode * -WriteCompactIndex(jsbytecode *pc, size_t index) -{ - size_t next; - - while ((next = index >> 7) != 0) { - *pc++ = (jsbytecode)(index | 0x80); - index = next; - } - *pc++ = (jsbytecode)index; - return pc; -} - -static jsbytecode * -ReadCompactIndex(jsbytecode *pc, size_t *result) -{ - size_t nextByte; - - nextByte = *pc++; - if ((nextByte & 0x80) == 0) { - /* - * Short-circuit the most common case when compact index <= 127. - */ - *result = nextByte; - } else { - size_t shift = 7; - *result = 0x7F & nextByte; - do { - nextByte = *pc++; - *result |= (nextByte & 0x7F) << shift; - shift += 7; - } while ((nextByte & 0x80) != 0); - } - return pc; -} - -typedef struct RECapture { - ptrdiff_t index; /* start of contents, -1 for empty */ - size_t 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; - ptrdiff_t index; /* progress in text */ - size_t parenSoFar; /* highest indexed paren started */ - union { - struct { - uintN min; /* current quantifier limits */ - uintN 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 */ - size_t parenIndex; /* start index of saved paren contents */ - size_t parenCount; /* # of saved paren contents */ - size_t saveStateStackTop; /* 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; /* text base address */ - const jschar *cpend; /* text limit address */ - - REProgState *stateStack; /* stack of state of current parents */ - size_t stateStackTop; - size_t stateStackLimit; - - REBackTrackData *backTrackStack;/* stack of matched-so-far positions */ - REBackTrackData *backTrackSP; - size_t backTrackStackSize; - size_t cursz; /* size of current stack entry */ - - JSArenaPool pool; /* It's faster to use one malloc'd pool - 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; - size_t 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; - - if (state->treeDepth == TREE_DEPTH_MAX) { - js_ReportCompileErrorNumber(state->context, state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_REGEXP_TOO_COMPLEX); - return JS_FALSE; - } - ++state->treeDepth; - - /* - * 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. - */ - 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, , uch1, uch2, , ..., - JUMP, ... 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, , uch1, uch2, , ..., - JUMP, ... 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, , uch1, uch2, , ..., - JUMP, ... ENDALT */ - state->progLength += 13; - } - else { - /* ALT, , ..., JUMP, ... 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_ReportCompileErrorNumberUC(state->context, state->tokenStream, - JSREPORT_TS | 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); -static intN ParseMinMaxQuantifier(CompilerState *state, JSBool ignoreValues); - -/* - * 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) -{ - size_t 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; - - for (;;) { - parenIndex = state->parenCount; - if (state->cp == state->cpend) { - /* - * If we are at the end of the regexp and we're short one or more - * operands, the regexp must have the form /x|/ or some such, with - * left parentheses making us short more than one operand. - */ - if (operatorSP >= operandSP) { - operand = NewRENode(state, REOP_EMPTY); - if (!operand) - goto out; - goto pushOperand; - } - } else { - switch (*state->cp) { - case '(': - ++state->cp; - if (state->cp + 1 < state->cpend && - *state->cp == '?' && - (state->cp[1] == '=' || - state->cp[1] == '!' || - state->cp[1] == ':')) { - switch (state->cp[1]) { - case '=': - op = REOP_ASSERT; - /* ASSERT, , ... ASSERTTEST */ - state->progLength += 4; - break; - case '!': - op = REOP_ASSERT_NOT; - /* ASSERTNOT, , ... ASSERTNOTTEST */ - state->progLength += 4; - break; - default: - op = REOP_LPARENNON; - break; - } - state->cp += 2; - } else { - op = REOP_LPAREN; - /* LPAREN, , ... RPAREN, */ - state->progLength - += 2 * (1 + GetCompactIndexWidth(parenIndex)); - state->parenCount++; - if (state->parenCount == 65535) { - js_ReportCompileErrorNumber(state->context, - state->tokenStream, - JSREPORT_TS | - JSREPORT_ERROR, - JSMSG_TOO_MANY_PARENS); - goto out; - } - } - goto pushOperator; - - case ')': - /* - * If there's no stacked open parenthesis, throw syntax error. - */ - for (i = operatorSP - 1; ; i--) { - if (i < 0) { - js_ReportCompileErrorNumber(state->context, - state->tokenStream, - JSREPORT_TS | - JSREPORT_ERROR, - JSMSG_UNMATCHED_RIGHT_PAREN); - goto out; - } - if (operatorStack[i].op == REOP_ASSERT || - operatorStack[i].op == REOP_ASSERT_NOT || - operatorStack[i].op == REOP_LPARENNON || - operatorStack[i].op == REOP_LPAREN) { - break; - } - } - /* FALL THROUGH */ - - 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 no stacked open parenthesis, throw syntax error. - */ - for (i = operatorSP - 1; ; i--) { - if (i < 0) { - js_ReportCompileErrorNumber(state->context, - state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_UNMATCHED_RIGHT_PAREN); - goto out; - } - if (operatorStack[i].op == REOP_ASSERT || - operatorStack[i].op == REOP_ASSERT_NOT || - operatorStack[i].op == REOP_LPARENNON || - operatorStack[i].op == REOP_LPAREN) { - break; - } - } - ++state->cp; - - /* Process everything on the stack until the open parenthesis. */ - for (;;) { - 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; - if (state->treeDepth == TREE_DEPTH_MAX) { - js_ReportCompileErrorNumber(state->context, - state->tokenStream, - JSREPORT_TS | - JSREPORT_ERROR, - JSMSG_REGEXP_TOO_COMPLEX); - goto out; - } - ++state->treeDepth; - /* FALL THROUGH */ - - 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; - - case '{': - { - const jschar *errp = state->cp; - - if (ParseMinMaxQuantifier(state, JS_TRUE) < 0) { - /* - * This didn't even scan correctly as a quantifier, so we should - * treat it as flat. - */ - op = REOP_CONCAT; - goto pushOperator; - } - - state->cp = errp; - /* FALL THROUGH */ - } - - case '+': - case '*': - case '?': - js_ReportCompileErrorNumberUC(state->context, state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_QUANTIFIER, state->cp); - result = JS_FALSE; - goto out; - - 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; -} - -/* - * Hack two bits in CompilerState.flags, for use within FindParenCount to flag - * its being on the stack, and to propagate errors to its callers. - */ -#define JSREG_FIND_PAREN_COUNT 0x8000 -#define JSREG_FIND_PAREN_ERROR 0x4000 - -/* - * Magic return value from FindParenCount and GetDecimalValue, to indicate - * overflow beyond GetDecimalValue's max parameter, or a computed maximum if - * its findMax parameter is non-null. - */ -#define OVERFLOW_VALUE ((uintN)-1) - -static uintN -FindParenCount(CompilerState *state) -{ - CompilerState temp; - int i; - - if (state->flags & JSREG_FIND_PAREN_COUNT) - return OVERFLOW_VALUE; - - /* - * Copy state into temp, flag it so we never report an invalid backref, - * and reset its members to parse the entire regexp. This is obviously - * suboptimal, but GetDecimalValue calls us only if a backref appears to - * refer to a forward parenthetical, which is rare. - */ - temp = *state; - temp.flags |= JSREG_FIND_PAREN_COUNT; - temp.cp = temp.cpbegin; - temp.parenCount = 0; - temp.classCount = 0; - temp.progLength = 0; - temp.treeDepth = 0; - temp.classBitmapsMem = 0; - for (i = 0; i < CLASS_CACHE_SIZE; i++) - temp.classCache[i].start = NULL; - - if (!ParseRegExp(&temp)) { - state->flags |= JSREG_FIND_PAREN_ERROR; - return OVERFLOW_VALUE; - } - return temp.parenCount; -} - -/* - * Extract and return a decimal value at state->cp. The initial character c - * has already been read. Return OVERFLOW_VALUE if the result exceeds max. - * Callers who pass a non-null findMax should test JSREG_FIND_PAREN_ERROR in - * state->flags to discover whether an error occurred under findMax. - */ -static uintN -GetDecimalValue(jschar c, uintN max, uintN (*findMax)(CompilerState *state), - CompilerState *state) -{ - uintN value = JS7_UNDEC(c); - JSBool overflow = (value > max && (!findMax || value > findMax(state))); - - /* The following restriction allows simpler overflow checks. */ - JS_ASSERT(max <= ((uintN)-1 - 9) / 10); - while (state->cp < state->cpend) { - c = *state->cp; - if (!JS7_ISDEC(c)) - break; - value = 10 * value + JS7_UNDEC(c); - if (!overflow && value > max && (!findMax || value > findMax(state))) - overflow = JS_TRUE; - ++state->cp; - } - return overflow ? OVERFLOW_VALUE : 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) -{ - uintN max = 0; - JSBool inRange = JS_FALSE; - jschar c, rangeStart = 0; - uintN n, digit, nDigits, i; - - 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; - - 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, - JSREPORT_TS | 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': - /* Give a strict warning. See also the note below. */ - if (!js_ReportCompileErrorNumber(state->context, - state->tokenStream, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_INVALID_BACKREF)) { - return JS_FALSE; - } - doOctal: - num = 0; - while (state->cp < state->cpend) { - c = *state->cp; - if (c < '0' || '7' < c) - break; - state->cp++; - tmp = 8 * num + (uintN)JS7_UNDEC(c); - if (tmp > 0377) - break; - num = tmp; - } - 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 = GetDecimalValue(c, state->parenCount, FindParenCount, state); - if (state->flags & JSREG_FIND_PAREN_ERROR) - return JS_FALSE; - if (num == OVERFLOW_VALUE) { - /* Give a strict mode warning. */ - if (!js_ReportCompileErrorNumber(state->context, - state->tokenStream, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - (c >= '8') - ? JSMSG_INVALID_BACKREF - : JSMSG_BAD_BACKREF)) { - return JS_FALSE; - } - - /* - * Note: ECMA 262, 15.10.2.9 says that we should throw a syntax - * error here. However, for compatibility with IE, we treat the - * whole backref as flat if the first character in it is not a - * valid octal character, and as an octal escape otherwise. - */ - state->cp = termStart; - if (c >= '8') { - /* Treat this as flat. termStart - 1 is the \. */ - c = '\\'; - goto asFlat; - } - - /* Treat this as an octal escape. */ - goto doOctal; - } - JS_ASSERT(1 <= num && num <= 0x10000); - state->result = NewRENode(state, REOP_BACKREF); - if (!state->result) - return JS_FALSE; - state->result->u.parenIndex = num - 1; - state->progLength - += 1 + GetCompactIndexWidth(state->result->u.parenIndex); - 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; - for (;;) { - if (state->cp == state->cpend) { - js_ReportCompileErrorNumberUC(state->context, state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_UNTERM_CLASS, termStart); - - return JS_FALSE; - } - if (*state->cp == '\\') { - state->cp++; - if (state->cp != state->cpend) - state->cp++; - continue; - } - if (*state->cp == ']') { - state->result->u.ucclass.kidlen = state->cp - termStart; - break; - } - state->cp++; - } - for (i = 0; i < CLASS_CACHE_SIZE; i++) { - if (!state->classCache[i].start) { - state->classCache[i].start = termStart; - state->classCache[i].length = state->result->u.ucclass.kidlen; - state->classCache[i].index = state->classCount; - break; - } - if (state->classCache[i].length == - state->result->u.ucclass.kidlen) { - for (n = 0; ; n++) { - if (n == state->classCache[i].length) { - state->result->u.ucclass.index - = state->classCache[i].index; - goto claim; - } - if (state->classCache[i].start[n] != termStart[n]) - break; - } - } - } - state->result->u.ucclass.index = state->classCount++; - - claim: - /* - * 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; - /* - * Update classBitmapsMem with number of bytes to hold bmsize bits, - * which is (bitsCount + 7) / 8 or (highest_bit + 1 + 7) / 8 - * or highest_bit / 8 + 1 where highest_bit is u.ucclass.bmsize. - */ - n = (state->result->u.ucclass.bmsize >> 3) + 1; - if (n > CLASS_BITMAPS_MEM_LIMIT - state->classBitmapsMem) { - js_ReportCompileErrorNumber(state->context, state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_REGEXP_TOO_COMPLEX); - return JS_FALSE; - } - state->classBitmapsMem += n; - /* CLASS, */ - state->progLength - += 1 + GetCompactIndexWidth(state->result->u.ucclass.index); - break; - - case '.': - state->result = NewRENode(state, REOP_DOT); - goto doSimple; - - case '{': - { - const jschar *errp = state->cp--; - intN err; - - err = ParseMinMaxQuantifier(state, JS_TRUE); - state->cp = errp; - - if (err < 0) - goto asFlat; - - /* FALL THROUGH */ - } - case '*': - case '+': - case '?': - js_ReportCompileErrorNumberUC(state->context, state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_QUANTIFIER, state->cp - 1); - return JS_FALSE; - default: -asFlat: - 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 = (uintN)-1; - /* , ... */ - 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 = (uintN)-1; - /* , ... */ - 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; - /* , ... */ - state->progLength += 4; - goto quantifier; - case '{': /* balance '}' */ - { - intN err; - const jschar *errp = state->cp; - - err = ParseMinMaxQuantifier(state, JS_FALSE); - if (err == 0) - goto quantifier; - if (err == -1) - return JS_TRUE; - - js_ReportCompileErrorNumberUC(state->context, - state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - err, errp); - return JS_FALSE; - } - default:; - } - } - return JS_TRUE; - -quantifier: - if (state->treeDepth == TREE_DEPTH_MAX) { - js_ReportCompileErrorNumber(state->context, state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_REGEXP_TOO_COMPLEX); - return JS_FALSE; - } - - ++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; -} - -static intN -ParseMinMaxQuantifier(CompilerState *state, JSBool ignoreValues) -{ - uintN min, max; - jschar c; - const jschar *errp = state->cp++; - - c = *state->cp; - if (JS7_ISDEC(c)) { - ++state->cp; - min = GetDecimalValue(c, 0xFFFF, NULL, state); - c = *state->cp; - - if (!ignoreValues && min == OVERFLOW_VALUE) - return JSMSG_MIN_TOO_BIG; - - if (c == ',') { - c = *++state->cp; - if (JS7_ISDEC(c)) { - ++state->cp; - max = GetDecimalValue(c, 0xFFFF, NULL, state); - c = *state->cp; - if (!ignoreValues && max == OVERFLOW_VALUE) - return JSMSG_MAX_TOO_BIG; - if (!ignoreValues && min > max) - return JSMSG_OUT_OF_ORDER; - } else { - max = (uintN)-1; - } - } 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, , , ... - * where is written as compact(max+1) to make - * (uintN)-1 sentinel to occupy 1 byte, not width_of(max)+1. - */ - state->progLength += (1 + GetCompactIndexWidth(min) - + GetCompactIndexWidth(max + 1) - +3); - return 0; - } - } - - state->cp = errp; - return -1; -} - -static JSBool -SetForwardJumpOffset(jsbytecode *jump, jsbytecode *target) -{ - ptrdiff_t offset = target - jump; - - /* Check that target really points forward. */ - JS_ASSERT(offset >= 2); - if ((size_t)offset > OFFSET_MAX) - return JS_FALSE; - - jump[0] = JUMP_OFFSET_HI(offset); - jump[1] = JUMP_OFFSET_LO(offset); - return JS_TRUE; -} - -/* - * Generate bytecode for the tree rooted at t using an explicit stack instead - * of recursion. - */ -static jsbytecode * -EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth, - jsbytecode *pc, RENode *t) -{ - EmitStateStackEntry *emitStateSP, *emitStateStack; - RECharSet *charSet; - REOp op; - - if (treeDepth == 0) { - emitStateStack = NULL; - } else { - emitStateStack = - (EmitStateStackEntry *)JS_malloc(state->context, - sizeof(EmitStateStackEntry) * - treeDepth); - if (!emitStateStack) - return NULL; - } - emitStateSP = emitStateStack; - op = t->op; - - for (;;) { - *pc++ = op; - switch (op) { - case REOP_EMPTY: - --pc; - break; - - case REOP_ALTPREREQ2: - case REOP_ALTPREREQ: - JS_ASSERT(emitStateSP); - emitStateSP->altHead = pc - 1; - 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; /* offset to next alternate */ - pc += OFFSET_LEN; - - emitStateSP->continueNode = t; - emitStateSP->continueOp = REOP_JUMP; - emitStateSP->jumpToJumpFlag = JS_FALSE; - ++emitStateSP; - JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); - t = (RENode *) t->kid; - op = t->op; - continue; - - case REOP_JUMP: - emitStateSP->nextTermFixup = pc; /* offset to following term */ - pc += OFFSET_LEN; - if (!SetForwardJumpOffset(emitStateSP->nextAltFixup, pc)) - goto jump_too_big; - emitStateSP->continueOp = REOP_ENDALT; - ++emitStateSP; - JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); - t = t->u.kid2; - op = t->op; - continue; - - case REOP_ENDALT: - /* - * If we already patched emitStateSP->nextTermFixup to jump to - * a nearer jump, to avoid 16-bit immediate offset overflow, we - * are done here. - */ - if (emitStateSP->jumpToJumpFlag) - break; - - /* - * Fix up the REOP_JUMP offset to go to the op after REOP_ENDALT. - * REOP_ENDALT is executed only on successful match of the last - * alternate in a group. - */ - if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc)) - goto jump_too_big; - if (t->op != REOP_ALT) { - if (!SetForwardJumpOffset(emitStateSP->endTermFixup, pc)) - goto jump_too_big; - } - - /* - * If the program is bigger than the REOP_JUMP offset range, then - * we must check for alternates before this one that are part of - * the same group, and fix up their jump offsets to target jumps - * close enough to fit in a 16-bit unsigned offset immediate. - */ - if ((size_t)(pc - re->program) > OFFSET_MAX && - emitStateSP > emitStateStack) { - EmitStateStackEntry *esp, *esp2; - jsbytecode *alt, *jump; - ptrdiff_t span, header; - - esp2 = emitStateSP; - alt = esp2->altHead; - for (esp = esp2 - 1; esp >= emitStateStack; --esp) { - if (esp->continueOp == REOP_ENDALT && - !esp->jumpToJumpFlag && - esp->nextTermFixup + OFFSET_LEN == alt && - (size_t)(pc - ((esp->continueNode->op != REOP_ALT) - ? esp->endTermFixup - : esp->nextTermFixup)) > OFFSET_MAX) { - alt = esp->altHead; - jump = esp->nextTermFixup; - - /* - * The span must be 1 less than the distance from - * jump offset to jump offset, so we actually jump - * to a REOP_JUMP bytecode, not to its offset! - */ - for (;;) { - JS_ASSERT(jump < esp2->nextTermFixup); - span = esp2->nextTermFixup - jump - 1; - if ((size_t)span <= OFFSET_MAX) - break; - do { - if (--esp2 == esp) - goto jump_too_big; - } while (esp2->continueOp != REOP_ENDALT); - } - - jump[0] = JUMP_OFFSET_HI(span); - jump[1] = JUMP_OFFSET_LO(span); - - if (esp->continueNode->op != REOP_ALT) { - /* - * We must patch the offset at esp->endTermFixup - * as well, for the REOP_ALTPREREQ{,2} opcodes. - * If we're unlucky and endTermFixup is more than - * OFFSET_MAX bytes from its target, we cheat by - * jumping 6 bytes to the jump whose offset is at - * esp->nextTermFixup, which has the same target. - */ - jump = esp->endTermFixup; - header = esp->nextTermFixup - jump; - span += header; - if ((size_t)span > OFFSET_MAX) - span = header; - - jump[0] = JUMP_OFFSET_HI(span); - jump[1] = JUMP_OFFSET_LO(span); - } - - esp->jumpToJumpFlag = JS_TRUE; - } - } - } - break; - - case REOP_ALT: - JS_ASSERT(emitStateSP); - emitStateSP->altHead = pc - 1; - emitStateSP->nextAltFixup = pc; /* offset to next alternate */ - pc += OFFSET_LEN; - emitStateSP->continueNode = t; - emitStateSP->continueOp = REOP_JUMP; - emitStateSP->jumpToJumpFlag = JS_FALSE; - ++emitStateSP; - JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); - t = t->kid; - op = t->op; - continue; - - case REOP_FLAT: - /* - * Coalesce FLATs if possible and if it would not increase bytecode - * beyond preallocated limit. The latter happens only when bytecode - * size for coalesced string with offset p and length 2 exceeds 6 - * bytes preallocated for 2 single char nodes, i.e. when - * 1 + GetCompactIndexWidth(p) + GetCompactIndexWidth(2) > 6 or - * GetCompactIndexWidth(p) > 4. - * Since when GetCompactIndexWidth(p) <= 4 coalescing of 3 or more - * nodes strictly decreases bytecode size, the check has to be - * done only for the first coalescing. - */ - if (t->kid && - GetCompactIndexWidth((jschar *)t->kid - state->cpbegin) <= 4) - { - 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) { - pc[-1] = (state->flags & JSREG_FOLD) ? REOP_FLATi : REOP_FLAT; - pc = WriteCompactIndex(pc, (jschar *)t->kid - state->cpbegin); - pc = WriteCompactIndex(pc, t->u.flat.length); - } else if (t->u.flat.chr < 256) { - pc[-1] = (state->flags & JSREG_FOLD) ? REOP_FLAT1i : REOP_FLAT1; - *pc++ = (jsbytecode) t->u.flat.chr; - } else { - pc[-1] = (state->flags & JSREG_FOLD) - ? REOP_UCFLAT1i - : REOP_UCFLAT1; - SET_ARG(pc, t->u.flat.chr); - pc += ARG_LEN; - } - break; - - case REOP_LPAREN: - JS_ASSERT(emitStateSP); - pc = WriteCompactIndex(pc, t->u.parenIndex); - emitStateSP->continueNode = t; - emitStateSP->continueOp = REOP_RPAREN; - ++emitStateSP; - JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); - t = (RENode *) t->kid; - op = t->op; - continue; - - case REOP_RPAREN: - pc = WriteCompactIndex(pc, t->u.parenIndex); - break; - - case REOP_BACKREF: - pc = WriteCompactIndex(pc, t->u.parenIndex); - break; - - case REOP_ASSERT: - JS_ASSERT(emitStateSP); - emitStateSP->nextTermFixup = pc; - pc += OFFSET_LEN; - emitStateSP->continueNode = t; - emitStateSP->continueOp = REOP_ASSERTTEST; - ++emitStateSP; - JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); - t = (RENode *) t->kid; - op = t->op; - continue; - - case REOP_ASSERTTEST: - case REOP_ASSERTNOTTEST: - if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc)) - goto jump_too_big; - break; - - case REOP_ASSERT_NOT: - JS_ASSERT(emitStateSP); - emitStateSP->nextTermFixup = pc; - pc += OFFSET_LEN; - emitStateSP->continueNode = t; - emitStateSP->continueOp = REOP_ASSERTNOTTEST; - ++emitStateSP; - JS_ASSERT((size_t)(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 == (uintN)-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 == (uintN) -1) { - pc[-1] = (t->u.range.greedy) ? REOP_PLUS : REOP_MINIMALPLUS; - } else { - if (!t->u.range.greedy) - pc[-1] = REOP_MINIMALQUANT; - pc = WriteCompactIndex(pc, t->u.range.min); - /* - * Write max + 1 to avoid using size_t(max) + 1 bytes - * for (uintN)-1 sentinel. - */ - pc = WriteCompactIndex(pc, t->u.range.max + 1); - } - emitStateSP->nextTermFixup = pc; - pc += OFFSET_LEN; - emitStateSP->continueNode = t; - emitStateSP->continueOp = REOP_ENDCHILD; - ++emitStateSP; - JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth); - t = (RENode *) t->kid; - op = t->op; - continue; - - case REOP_ENDCHILD: - if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc)) - goto jump_too_big; - break; - - case REOP_CLASS: - if (!t->u.ucclass.sense) - pc[-1] = REOP_NCLASS; - pc = WriteCompactIndex(pc, t->u.ucclass.index); - 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) { - op = t->op; - } else { - if (emitStateSP == emitStateStack) - break; - --emitStateSP; - t = emitStateSP->continueNode; - op = emitStateSP->continueOp; - } - } - - cleanup: - if (emitStateStack) - JS_free(state->context, emitStateStack); - return pc; - - jump_too_big: - js_ReportCompileErrorNumber(state->context, state->tokenStream, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_REGEXP_TOO_COMPLEX); - pc = NULL; - goto cleanup; -} - - -JSRegExp * -js_NewRegExp(JSContext *cx, JSTokenStream *ts, - JSString *str, uintN flags, JSBool flat) -{ - JSRegExp *re; - void *mark; - CompilerState state; - size_t resize; - jsbytecode *endPC; - uintN i; - size_t len; - - re = NULL; - mark = JS_ARENA_MARK(&cx->tempPool); - len = JSSTRING_LENGTH(str); - - state.context = cx; - state.tokenStream = ts; - state.cpbegin = state.cp = JSSTRING_CHARS(str); - state.cpend = state.cp + len; - state.flags = flags; - state.parenCount = 0; - state.classCount = 0; - state.progLength = 0; - state.treeDepth = 0; - state.classBitmapsMem = 0; - for (i = 0; i < CLASS_CACHE_SIZE; i++) - state.classCache[i].start = NULL; - - if (len != 0 && flat) { - state.result = NewRENode(&state, REOP_FLAT); - state.result->u.flat.chr = *state.cpbegin; - state.result->u.flat.length = len; - state.result->kid = (void *) state.cpbegin; - /* Flat bytecode: REOP_FLAT compact(string_offset) compact(len). */ - state.progLength += 1 + GetCompactIndexWidth(0) - + GetCompactIndexWidth(len); - } else { - if (!ParseRegExp(&state)) - goto out; - } - resize = offsetof(JSRegExp, program) + state.progLength + 1; - re = (JSRegExp *) JS_malloc(cx, resize); - if (!re) - goto out; - - re->nrefs = 1; - JS_ASSERT(state.classBitmapsMem <= CLASS_BITMAPS_MEM_LIMIT); - re->classCount = state.classCount; - if (re->classCount) { - re->classList = (RECharSet *) - JS_malloc(cx, re->classCount * sizeof(RECharSet)); - if (!re->classList) { - js_DestroyRegExp(cx, re); - re = NULL; - goto out; - } - } else { - re->classList = NULL; - } - endPC = EmitREBytecode(&state, re, state.treeDepth, re->program, state.result); - if (!endPC) { - js_DestroyRegExp(cx, re); - re = NULL; - goto out; - } - *endPC++ = REOP_END; - /* - * Check whether size was overestimated and shrink using realloc. - * This is safe since no pointers to newly parsed regexp or its parts - * besides re exist here. - */ - if ((size_t)(endPC - re->program) != state.progLength + 1) { - JSRegExp *tmp; - JS_ASSERT((size_t)(endPC - re->program) < state.progLength + 1); - resize = offsetof(JSRegExp, program) + (endPC - re->program); - tmp = (JSRegExp *) JS_realloc(cx, re, resize); - if (tmp) - re = tmp; - } - - re->flags = flags; - re->cloneIndex = 0; - re->parenCount = state.parenCount; - 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, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_FLAG, charBuf); - return NULL; - } - } - } - return js_NewRegExp(cx, ts, str, flags, flat); -} - -/* - * 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, - size_t parenIndex, size_t parenCount) -{ - size_t i; - REBackTrackData *result = - (REBackTrackData *) ((char *)gData->backTrackSP + gData->cursz); - - size_t sz = sizeof(REBackTrackData) + - gData->stateStackTop * sizeof(REProgState) + - parenCount * sizeof(RECapture); - - ptrdiff_t btsize = gData->backTrackStackSize; - ptrdiff_t btincr = ((char *)result + sz) - - ((char *)gData->backTrackStack + btsize); - - if (btincr > 0) { - ptrdiff_t offset = (char *)result - (char *)gData->backTrackStack; - - btincr = JS_ROUNDUP(btincr, btsize); - JS_ARENA_GROW_CAST(gData->backTrackStack, REBackTrackData *, - &gData->pool, btsize, btincr); - if (!gData->backTrackStack) - return NULL; - gData->backTrackStackSize = btsize + btincr; - 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->saveStateStackTop = gData->stateStackTop; - JS_ASSERT(gData->stateStackTop); - memcpy(result + 1, gData->stateStack, - sizeof(REProgState) * result->saveStateStackTop); - - if (parenCount != 0) { - result->parenIndex = parenIndex; - memcpy((char *)(result + 1) + - sizeof(REProgState) * result->saveStateStackTop, - &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, - size_t length) -{ - size_t i; - if (length > gData->cpend - x->cp) - 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, - size_t length) -{ - size_t i; - JS_ASSERT(gData->cpend >= x->cp); - if (length > (size_t)(gData->cpend - x->cp)) - 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, size_t parenIndex) -{ - size_t len, i; - const jschar *parenContent; - RECapture *cap = &x->parens[parenIndex]; - - if (cap->index == -1) - return x; - - len = cap->length; - if (x->cp + len > gData->cpend) - return NULL; - - parenContent = &gData->cpbegin[cap->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 >> 3); - 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 >> 3); - uintN byteIndex2 = (uintN)(c2 >> 3); - - 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, *end; - JSBool inRange = JS_FALSE; - jschar rangeStart = 0; - uintN byteLength, n; - jschar c, thisCh; - intN nDigits, i; - - JS_ASSERT(!charSet->converted); - /* - * Assert that startIndex and length points to chars inside [] inside - * source string. - */ - JS_ASSERT(1 <= charSet->u.src.startIndex); - JS_ASSERT(charSet->u.src.startIndex - < JSSTRING_LENGTH(gData->regexp->source)); - JS_ASSERT(charSet->u.src.length <= JSSTRING_LENGTH(gData->regexp->source) - - 1 - charSet->u.src.startIndex); - - charSet->converted = JS_TRUE; - src = JSSTRING_CHARS(gData->regexp->source) + charSet->u.src.startIndex; - end = src + charSet->u.src.length; - JS_ASSERT(src[-1] == '['); - JS_ASSERT(end[0] == ']'); - - byteLength = (charSet->length >> 3) + 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) -{ - if (JS_ATOMIC_DECREMENT(&re->nrefs) == 0) { - if (re->classList) { - uintN i; - 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 limit = gData->stateStackLimit; - size_t sz = sizeof(REProgState) * limit; - - JS_ARENA_GROW_CAST(gData->stateStack, REProgState *, &gData->pool, sz, sz); - if (!gData->stateStack) { - gData->ok = JS_FALSE; - return JS_FALSE; - } - gData->stateStackLimit = limit + limit; - return JS_TRUE; -} - -#define PUSH_STATE_STACK(data) \ - JS_BEGIN_MACRO \ - ++(data)->stateStackTop; \ - if ((data)->stateStackTop == (data)->stateStackLimit && \ - !ReallocStateStack((data))) { \ - return NULL; \ - } \ - JS_END_MACRO - -/* - * 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; - size_t parenIndex; - size_t 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) { - case REOP_BOL: - if (x->cp != gData->cpbegin) { - if (!gData->cx->regExpStatics.multiline && - !(gData->regexp->flags & JSREG_MULTILINE)) { - break; - } - if (!RE_IS_LINE_TERM(x->cp[-1])) - break; - } - result = x; - break; - case REOP_EOL: - if (x->cp != gData->cpend) { - if (!gData->cx->regExpStatics.multiline && - !(gData->regexp->flags & JSREG_MULTILINE)) { - break; - } - if (!RE_IS_LINE_TERM(*x->cp)) - 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: - pc = ReadCompactIndex(pc, &parenIndex); - JS_ASSERT(parenIndex < gData->regexp->parenCount); - result = BackrefMatcher(gData, x, parenIndex); - break; - case REOP_FLAT: - pc = ReadCompactIndex(pc, &offset); - JS_ASSERT(offset < JSSTRING_LENGTH(gData->regexp->source)); - pc = ReadCompactIndex(pc, &length); - JS_ASSERT(1 <= length); - JS_ASSERT(length <= JSSTRING_LENGTH(gData->regexp->source) - offset); - if (length <= (size_t)(gData->cpend - x->cp)) { - source = JSSTRING_CHARS(gData->regexp->source) + offset; - 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: - pc = ReadCompactIndex(pc, &offset); - JS_ASSERT(offset < JSSTRING_LENGTH(gData->regexp->source)); - pc = ReadCompactIndex(pc, &length); - JS_ASSERT(1 <= length); - JS_ASSERT(length <= JSSTRING_LENGTH(gData->regexp->source) - offset); - 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: - pc = ReadCompactIndex(pc, &index); - JS_ASSERT(index < gData->regexp->classCount); - if (x->cp != gData->cpend) { - charSet = &gData->regexp->classList[index]; - JS_ASSERT(charSet->converted); - ch = *x->cp; - index = ch >> 3; - if (charSet->length != 0 && - ch <= charSet->length && - (charSet->u.bits[index] & (1 << (ch & 0x7)))) { - result = x; - result->cp++; - } - } - break; - case REOP_NCLASS: - pc = ReadCompactIndex(pc, &index); - JS_ASSERT(index < gData->regexp->classCount); - if (x->cp != gData->cpend) { - charSet = &gData->regexp->classList[index]; - JS_ASSERT(charSet->converted); - ch = *x->cp; - index = ch >> 3; - if (charSet->length == 0 || - ch > charSet->length || - !(charSet->u.bits[index] & (1 << (ch & 0x7)))) { - result = x; - result->cp++; - } - } - break; - default: - JS_ASSERT(JS_FALSE); - } - if (result) { - if (update) - *startpc = pc; - else - x->cp = startcp; - return result; - } - x->cp = startcp; - return NULL; -} - -static REMatchState * -ExecuteREBytecode(REGlobalData *gData, REMatchState *x) -{ - REMatchState *result = NULL; - REBackTrackData *backTrackData; - jsbytecode *nextpc; - REOp nextop; - RECapture *cap; - REProgState *curState; - const jschar *startcp; - size_t parenIndex, k; - size_t 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; - } - gData->skipped++; - x->cp++; - } - if (!anchor) - return NULL; - } - - for (;;) { - 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 >> 3; - if ((charSet->length == 0 || - matchCh1 > charSet->length || - !(charSet->u.bits[k] & (1 << (matchCh1 & 0x7)))) ^ - 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; - PUSH_STATE_STACK(gData); - 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; - } - 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; - pc += GET_OFFSET(pc); - op = (REOp) *pc++; - continue; - - /* - * Occurs at last (succesful) end of REOP_ALT, - */ - case REOP_ENDALT: - --gData->stateStackTop; - op = (REOp) *pc++; - continue; - - case REOP_LPAREN: - pc = ReadCompactIndex(pc, &parenIndex); - JS_ASSERT(parenIndex < gData->regexp->parenCount); - if (parenIndex + 1 > parenSoFar) - parenSoFar = parenIndex + 1; - x->parens[parenIndex].index = x->cp - gData->cpbegin; - x->parens[parenIndex].length = 0; - op = (REOp) *pc++; - continue; - - case REOP_RPAREN: - pc = ReadCompactIndex(pc, &parenIndex); - JS_ASSERT(parenIndex < gData->regexp->parenCount); - cap = &x->parens[parenIndex]; - - /* - * FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=346090 - * This wallpaper prevents a case where we somehow took a step - * backward in input while minimally-matching an empty string. - */ - if (x->cp < gData->cpbegin + cap->index) - cap->index = -1; - 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; - } - 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; - PUSH_STATE_STACK(gData); - 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) && - pc == nextpc) { - result = NULL; - break; - } - 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; - PUSH_STATE_STACK(gData); - 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) - 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; - result = (!result) ? x : NULL; - break; - - case REOP_END: - if (x) - return x; - break; - - case REOP_STAR: - curState->u.quantifier.min = 0; - curState->u.quantifier.max = (uintN)-1; - goto quantcommon; - case REOP_PLUS: - curState->u.quantifier.min = 1; - curState->u.quantifier.max = (uintN)-1; - goto quantcommon; - case REOP_OPT: - curState->u.quantifier.min = 0; - curState->u.quantifier.max = 1; - goto quantcommon; - case REOP_QUANT: - pc = ReadCompactIndex(pc, &k); - curState->u.quantifier.min = k; - pc = ReadCompactIndex(pc, &k); - /* max is k - 1 to use one byte for (uintN)-1 sentinel. */ - curState->u.quantifier.max = k - 1; - JS_ASSERT(curState->u.quantifier.min - <= curState->u.quantifier.max); - quantcommon: - if (curState->u.quantifier.max == 0) { - pc = pc + GET_OFFSET(pc); - op = (REOp) *pc++; - result = x; - continue; - } - /* Step over */ - 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; - } - op = (REOp) *nextpc++; - result = x; - } - curState->index = startcp - gData->cpbegin; - curState->continue_op = REOP_REPEAT; - curState->continue_pc = pc; - curState->parenSoFar = parenSoFar; - PUSH_STATE_STACK(gData); - if (curState->u.quantifier.min == 0 && - !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; - do { - --gData->stateStackTop; - if (!result) { - /* Failed, see if we have enough children. */ - if (curState->u.quantifier.min == 0) - goto repeatDone; - goto break_switch; - } - if (curState->u.quantifier.min == 0 && - x->cp == gData->cpbegin + curState->index) { - /* matched an empty string, that'll get us nowhere */ - result = NULL; - goto break_switch; - } - if (curState->u.quantifier.min != 0) - curState->u.quantifier.min--; - if (curState->u.quantifier.max != (uintN) -1) - curState->u.quantifier.max--; - if (curState->u.quantifier.max == 0) - 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) - goto repeatDone; - result = NULL; - goto break_switch; - } - result = x; - } - curState->index = startcp - gData->cpbegin; - PUSH_STATE_STACK(gData); - if (curState->u.quantifier.min == 0 && - !PushBackTrackState(gData, REOP_REPEAT, - pc, x, startcp, - curState->parenSoFar, - parenSoFar - - curState->parenSoFar)) { - return NULL; - } - } while (*nextpc == REOP_ENDCHILD); - pc = nextpc; - op = (REOp) *pc++; - parenSoFar = curState->parenSoFar; - continue; - - repeatDone: - result = x; - pc += GET_OFFSET(pc); - goto break_switch; - - case REOP_MINIMALSTAR: - curState->u.quantifier.min = 0; - curState->u.quantifier.max = (uintN)-1; - goto minimalquantcommon; - case REOP_MINIMALPLUS: - curState->u.quantifier.min = 1; - curState->u.quantifier.max = (uintN)-1; - goto minimalquantcommon; - case REOP_MINIMALOPT: - curState->u.quantifier.min = 0; - curState->u.quantifier.max = 1; - goto minimalquantcommon; - case REOP_MINIMALQUANT: - pc = ReadCompactIndex(pc, &k); - curState->u.quantifier.min = k; - pc = ReadCompactIndex(pc, &k); - /* See REOP_QUANT comments about k - 1. */ - curState->u.quantifier.max = k - 1; - JS_ASSERT(curState->u.quantifier.min - <= curState->u.quantifier.max); - minimalquantcommon: - curState->index = x->cp - gData->cpbegin; - curState->parenSoFar = parenSoFar; - PUSH_STATE_STACK(gData); - if (curState->u.quantifier.min != 0) { - curState->continue_op = REOP_MINIMALREPEAT; - curState->continue_pc = pc; - /* step over */ - pc += OFFSET_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) { - /* - * Non-greedy failure - try to consume another child. - */ - if (curState->u.quantifier.max == (uintN) -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; - PUSH_STATE_STACK(gData); - op = (REOp) *pc++; - continue; - } - /* Don't need to adjust pc since we're going to pop. */ - break; - } - 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 != (uintN) -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; - PUSH_STATE_STACK(gData); - op = (REOp) *pc++; - continue; - } - curState->index = x->cp - gData->cpbegin; - curState->parenSoFar = parenSoFar; - PUSH_STATE_STACK(gData); - 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; - } - break_switch:; - } - - /* - * If the match failed and there's a backtrack option, take it. - * Otherwise this is a complete and utter failure. - */ - if (!result) { - if (gData->cursz == 0) - return NULL; - 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->saveStateStackTop; - JS_ASSERT(gData->stateStackTop); - - memcpy(gData->stateStack, backTrackData + 1, - sizeof(REProgState) * backTrackData->saveStateStackTop); - curState = &gData->stateStack[gData->stateStackTop - 1]; - - if (backTrackData->parenCount) { - memcpy(&x->parens[backTrackData->parenIndex], - (char *)(backTrackData + 1) + - sizeof(REProgState) * backTrackData->saveStateStackTop, - 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; - } - 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->backTrackStackSize = 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->stateStackLimit = 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, - offsetof(REMatchState, parens) - + re->parenCount * 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 = NULL; - - /* - * 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); - ok = gData.ok; - if (!ok) - goto out; - if (!result) { - *rval = JSVAL_NULL; - goto out; - } - cp = result->cp; - i = cp - gData.cpbegin; - *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_JSID(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_JSID(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_JSID(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 = js_EmptySubString; - } 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), - ATOM_TO_JSID(cx->runtime->atomState.indexAtom)); - DEFVAL(STRING_TO_JSVAL(str), - ATOM_TO_JSID(cx->runtime->atomState.inputAtom)); - } - -#undef DEFVAL - - res->lastMatch.chars = cp; - res->lastMatch.length = matchlen; - if (JS_VERSION_IS_1_2(cx)) { - /* - * JS1.2 emulated Perl4.0.1.8 (patch level 36) for global regexps used - * in scalar contexts, and unintentionally for the string.match "list" - * pseudo-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; - uint32 flagsword; - JSObject *obj; - - if (xdr->mode == JSXDR_ENCODE) { - re = (JSRegExp *) JS_GetPrivate(xdr->cx, *objp); - if (!re) - return JS_FALSE; - source = re->source; - flagsword = ((uint32)re->cloneIndex << 16) | re->flags; - } - if (!JS_XDRString(xdr, &source) || - !JS_XDRUint32(xdr, &flagsword)) { - return JS_FALSE; - } - if (xdr->mode == JSXDR_DECODE) { - obj = js_NewObject(xdr->cx, &js_RegExpClass, NULL, NULL); - if (!obj) - return JS_FALSE; - re = js_NewRegExp(xdr->cx, NULL, source, (uint16)flagsword, JS_FALSE); - if (!re) - return JS_FALSE; - if (!JS_SetPrivate(xdr->cx, obj, re) || - !js_SetLastIndex(xdr->cx, obj, 0)) { - js_DestroyRegExp(xdr->cx, re); - return JS_FALSE; - } - re->cloneIndex = (uint16)(flagsword >> 16); - *objp = obj; - } - 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}; - -JSBool -js_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, ok2; - JSObject *obj2; - size_t length, nbytes; - const jschar *cp, *start, *end; - jschar *nstart, *ncp, *tmp; - - 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 created; - } - } - 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); - } - } - - /* Escape any naked slashes in the regexp source. */ - length = JSSTRING_LENGTH(str); - start = JSSTRING_CHARS(str); - end = start + length; - nstart = ncp = NULL; - for (cp = start; cp < end; cp++) { - if (*cp == '/' && (cp == start || cp[-1] != '\\')) { - nbytes = (++length + 1) * sizeof(jschar); - if (!nstart) { - nstart = (jschar *) JS_malloc(cx, nbytes); - if (!nstart) - return JS_FALSE; - ncp = nstart + (cp - start); - js_strncpy(nstart, start, cp - start); - } else { - tmp = (jschar *) JS_realloc(cx, nstart, nbytes); - if (!tmp) { - JS_free(cx, nstart); - return JS_FALSE; - } - ncp = tmp + (ncp - nstart); - nstart = tmp; - } - *ncp++ = '\\'; - } - if (nstart) - *ncp++ = *cp; - } - - if (nstart) { - /* Don't forget to store the backstop after the new string. */ - JS_ASSERT((size_t)(ncp - nstart) == length); - *ncp = 0; - str = js_NewString(cx, nstart, length, 0); - if (!str) { - JS_free(cx, nstart); - return JS_FALSE; - } - argv[0] = STRING_TO_JSVAL(str); - } - } - - re = js_NewRegExpOpt(cx, NULL, str, opt, JS_FALSE); -created: - if (!re) - return JS_FALSE; - JS_LOCK_OBJ(cx, obj); - oldre = (JSRegExp *) JS_GetPrivate(cx, obj); - ok = JS_SetPrivate(cx, obj, re); - ok2 = js_SetLastIndex(cx, obj, 0); - JS_UNLOCK_OBJ(cx, obj); - if (!ok) { - js_DestroyRegExp(cx, re); - return JS_FALSE; - } - if (oldre) - js_DestroyRegExp(cx, oldre); - *rval = OBJECT_TO_JSVAL(obj); - return ok2; -} - -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, js_regexp_toString, 0,0,0}, -#endif - {js_toString_str, js_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_PRIMITIVE(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; - - /* - * regexp_compile does not use rval to root its temporaries - * so we can use it to root obj. - */ - *rval = OBJECT_TO_JSVAL(obj); - } - 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; - JSTempValueRooter tvr; - - str = js_NewStringCopyN(cx, chars, length, 0); - if (!str) - return NULL; - re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); - if (!re) - return NULL; - JS_PUSH_SINGLE_TEMP_ROOT(cx, STRING_TO_JSVAL(str), &tvr); - obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL); - if (!obj || !JS_SetPrivate(cx, obj, re) || !js_SetLastIndex(cx, obj, 0)) { - js_DestroyRegExp(cx, re); - obj = NULL; - } - JS_POP_TEMP_ROOT(cx, &tvr); - 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 deleted file mode 100644 index 50789832d..000000000 --- a/src/dom/js/jsregexp.h +++ /dev/null @@ -1,183 +0,0 @@ -/* -*- 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 -#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 $*) */ - uint16 parenCount; /* number of valid elements in parens[] */ - uint16 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 { - JSPackedBool converted; - JSPackedBool sense; - uint16 length; - union { - uint8 *bits; - struct { - size_t startIndex; - size_t 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 */ - uint16 flags; /* flags, see jsapi.h's JSREG_* defines */ - uint16 cloneIndex; /* index in fp->vars or funobj->slots of - cloned regexp object */ - size_t parenCount; /* number of parenthesized submatches */ - size_t 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); - -#define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs) -#define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re) - -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); - -/* - * Export js_regexp_toString to the decompiler. - */ -extern JSBool -js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); - -/* - * Create, serialize/deserialize, or clone a 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); - -/* - * Get and set the per-object (clone or clone-parent) lastIndex slot. - */ -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 deleted file mode 100644 index c043799dc..000000000 --- a/src/dom/js/jsscan.c +++ /dev/null @@ -1,2170 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set sw=4 ts=8 et tw=78: - * - * ***** 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 /* first to avoid trouble on some systems */ -#include -#include -#include -#ifdef HAVE_MEMORY_H -#include -#endif -#include -#include -#include -#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" -#include "jsscript.h" - -#if JS_HAS_XML_SUPPORT -#include "jsparse.h" -#include "jsxml.h" -#endif - -#define RESERVE_JAVA_KEYWORDS -#define RESERVE_ECMA_KEYWORDS - -#define MAX_KEYWORD_LENGTH 12 - -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}, - {js_default_str, 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}, - {js_var_str, 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; - size_t length; - JSAtom *atom; - - for (kw = keywords; kw->name; kw++) { - length = strlen(kw->name); - JS_ASSERT(length <= MAX_KEYWORD_LENGTH); - atom = js_Atomize(cx, kw->name, length, 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; -} - -#define TBMIN 64 - -static JSBool -GrowTokenBuf(JSStringBuffer *sb, size_t newlength) -{ - JSContext *cx; - jschar *base; - ptrdiff_t offset, length; - size_t tbsize; - JSArenaPool *pool; - - cx = sb->data; - base = sb->base; - offset = PTRDIFF(sb->ptr, base, jschar); - pool = &cx->tempPool; - if (!base) { - tbsize = TBMIN * sizeof(jschar); - length = TBMIN - 1; - JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize); - } else { - length = PTRDIFF(sb->limit, base, jschar); - tbsize = (length + 1) * sizeof(jschar); - length += length + 1; - JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize); - } - if (!base) { - JS_ReportOutOfMemory(cx); - sb->base = STRING_BUFFER_ERROR_BASE; - return JS_FALSE; - } - sb->base = base; - sb->limit = base + length; - sb->ptr = base + offset; - return JS_TRUE; -} - -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->tokenbuf.grow = GrowTokenBuf; - ts->tokenbuf.data = cx; - 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->flags & TSF_OWNFILENAME) - JS_free(cx, (void *) ts->filename); - if (ts->principals) - JSPRINCIPALS_DROP(cx, ts->principals); - return !ts->file || fclose(ts->file) == 0; -} - -JS_FRIEND_API(int) -js_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 = js_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); - } - - nl = ts->saveEOL; - if (!nl) { - /* - * Any one of \n, \r, or \r\n ends a line (the 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; - ts->saveEOL = nl; - } else { - ts->saveEOL = NULL; - } - 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; -} - -/* - * Peek n chars ahead into ts. Return true if n chars were read, false if - * there weren't enough characters in the input stream. This function cannot - * be used to peek into or past a newline. - */ -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; - if (c == '\n') { - UngetChar(ts, c); - 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; -} - -static JSBool -ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags, - uintN errorNumber, JSErrorReport *report, - JSBool charArgs, va_list ap) -{ - JSString *linestr = NULL; - JSTokenStream *ts = NULL; - JSCodeGenerator *cg = NULL; -#if JS_HAS_XML_SUPPORT - JSParseNode *pn = NULL; -#endif - JSErrorReporter onError; - JSTokenPos *tp; - JSStackFrame *fp; - uintN index; - char *message; - JSBool warning; - - memset(report, 0, sizeof (struct JSErrorReport)); - report->flags = flags; - report->errorNumber = errorNumber; - message = NULL; - - if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL, - errorNumber, &message, report, &warning, - charArgs, ap)) { - return JS_FALSE; - } - - js_AddRoot(cx, &linestr, "error line buffer"); - - switch (flags & JSREPORT_HANDLE) { - case JSREPORT_TS: - ts = handle; - break; - case JSREPORT_CG: - cg = handle; - break; -#if JS_HAS_XML_SUPPORT - case JSREPORT_PN: - pn = handle; - ts = pn->pn_ts; - break; -#endif - } - - 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. - */ - do { - if (ts) { - report->filename = ts->filename; -#if JS_HAS_XML_SUPPORT - if (pn) { - report->lineno = pn->pn_pos.begin.lineno; - if (report->lineno != ts->lineno) - break; - } -#endif - report->lineno = ts->lineno; - linestr = js_NewStringCopyN(cx, ts->linebuf.base, - PTRDIFF(ts->linebuf.limit, - ts->linebuf.base, - jschar), - 0); - report->linebuf = linestr - ? JS_GetStringBytes(linestr) - : NULL; - tp = &ts->tokens[(ts->cursor+ts->lookahead) & NTOKENS_MASK].pos; -#if JS_HAS_XML_SUPPORT - if (pn) - tp = &pn->pn_pos; -#endif - /* - * FIXME: What should instead happen here is that we should - * find error-tokens in userbuf, if !ts->file. That will - * allow us to deliver a more helpful error message, which - * includes all or part of the bad string or bad token. The - * code here yields something that looks truncated. - * See https://bugzilla.mozilla.org/show_bug.cgi?id=352970 - */ - index = 0; - if (tp->begin.lineno == tp->end.lineno) { - if (tp->begin.index < ts->linepos) - break; - - index = tp->begin.index - ts->linepos; - } - - report->tokenptr = linestr ? report->linebuf + index : NULL; - report->uclinebuf = linestr ? JS_GetStringChars(linestr) : NULL; - report->uctokenptr = linestr ? report->uclinebuf + index : NULL; - break; - } - - if (cg) { - report->filename = cg->filename; - report->lineno = CG_CURRENT_LINE(cg); - break; - } - - /* - * 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; - } - } - } while (0); - -#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. - */ - - /* - * Try to raise an exception only if there isn't one already set -- - * otherwise the exception will describe the last compile-time error, - * which is likely spurious. - */ - if (!ts || !(ts->flags & TSF_ERROR)) { - if (js_ErrorToException(cx, message, report)) - onError = NULL; - } - - /* - * Suppress any compile-time 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 && !JSREPORT_IS_WARNING(flags)) - onError = NULL; -#endif - if (onError) { - JSDebugErrorHook hook = cx->runtime->debugErrorHook; - - /* - * If debugErrorHook is present then we give it a chance to veto - * sending the error on to the regular error reporter. - */ - 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->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; -} - -JSBool -js_ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags, - uintN errorNumber, ...) -{ - va_list ap; - JSErrorReport report; - JSBool warning; - - if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx)) - return JS_TRUE; - - va_start(ap, errorNumber); - warning = ReportCompileErrorNumber(cx, handle, flags, errorNumber, - &report, JS_TRUE, ap); - va_end(ap); - - /* - * We have to do this here because js_ReportCompileErrorNumberUC doesn't - * need to do this. - */ - if (report.messageArgs) { - int i = 0; - while (report.messageArgs[i]) - JS_free(cx, (void *)report.messageArgs[i++]); - JS_free(cx, (void *)report.messageArgs); - } - - return warning; -} - -JSBool -js_ReportCompileErrorNumberUC(JSContext *cx, void *handle, uintN flags, - uintN errorNumber, ...) -{ - va_list ap; - JSErrorReport report; - JSBool warning; - - if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx)) - return JS_TRUE; - - va_start(ap, errorNumber); - warning = ReportCompileErrorNumber(cx, handle, flags, errorNumber, - &report, JS_FALSE, ap); - va_end(ap); - - if (report.messageArgs) - JS_free(cx, (void *)report.messageArgs); - - return warning; -} - -static JSBool -GrowStringBuffer(JSStringBuffer *sb, size_t newlength) -{ - ptrdiff_t offset; - jschar *bp; - - offset = PTRDIFF(sb->ptr, sb->base, jschar); - JS_ASSERT(offset >= 0); - newlength += offset + 1; - if ((size_t)offset < newlength && newlength < ~(size_t)0 / sizeof(jschar)) - bp = realloc(sb->base, newlength * sizeof(jschar)); - else - bp = NULL; - if (!bp) { - free(sb->base); - sb->base = STRING_BUFFER_ERROR_BASE; - return JS_FALSE; - } - sb->base = bp; - sb->ptr = bp + offset; - sb->limit = bp + newlength - 1; - return JS_TRUE; -} - -static void -FreeStringBuffer(JSStringBuffer *sb) -{ - JS_ASSERT(STRING_BUFFER_OK(sb)); - if (sb->base) - free(sb->base); -} - -void -js_InitStringBuffer(JSStringBuffer *sb) -{ - sb->base = sb->limit = sb->ptr = NULL; - sb->data = NULL; - sb->grow = GrowStringBuffer; - sb->free = FreeStringBuffer; -} - -void -js_FinishStringBuffer(JSStringBuffer *sb) -{ - sb->free(sb); -} - -#define ENSURE_STRING_BUFFER(sb,n) \ - ((sb)->ptr + (n) <= (sb)->limit || sb->grow(sb, n)) - -static void -FastAppendChar(JSStringBuffer *sb, jschar c) -{ - if (!STRING_BUFFER_OK(sb)) - return; - if (!ENSURE_STRING_BUFFER(sb, 1)) - return; - *sb->ptr++ = c; -} - -void -js_AppendChar(JSStringBuffer *sb, jschar c) -{ - jschar *bp; - - if (!STRING_BUFFER_OK(sb)) - return; - if (!ENSURE_STRING_BUFFER(sb, 1)) - return; - bp = sb->ptr; - *bp++ = c; - *bp = 0; - sb->ptr = bp; -} - -#if JS_HAS_XML_SUPPORT - -void -js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count) -{ - jschar *bp; - - if (!STRING_BUFFER_OK(sb) || count == 0) - return; - if (!ENSURE_STRING_BUFFER(sb, count)) - return; - for (bp = sb->ptr; count; --count) - *bp++ = c; - *bp = 0; - sb->ptr = bp; -} - -void -js_AppendCString(JSStringBuffer *sb, const char *asciiz) -{ - size_t length; - jschar *bp; - - if (!STRING_BUFFER_OK(sb) || *asciiz == '\0') - return; - length = strlen(asciiz); - if (!ENSURE_STRING_BUFFER(sb, length)) - return; - for (bp = sb->ptr; length; --length) - *bp++ = (jschar) *asciiz++; - *bp = 0; - sb->ptr = bp; -} - -void -js_AppendJSString(JSStringBuffer *sb, JSString *str) -{ - size_t length; - jschar *bp; - - if (!STRING_BUFFER_OK(sb)) - return; - length = JSSTRING_LENGTH(str); - if (length == 0 || !ENSURE_STRING_BUFFER(sb, length)) - return; - bp = sb->ptr; - js_strncpy(bp, JSSTRING_CHARS(str), length); - bp += length; - *bp = 0; - sb->ptr = bp; -} - -static JSBool -GetXMLEntity(JSContext *cx, JSTokenStream *ts) -{ - ptrdiff_t offset, length, i; - int32 c, d; - JSBool ispair; - jschar *bp, digit; - char *bytes; - JSErrNum msg; - - /* Put the entity, including the '&' already scanned, in ts->tokenbuf. */ - offset = PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar); - FastAppendChar(&ts->tokenbuf, '&'); - while ((c = GetChar(ts)) != ';') { - if (c == EOF || c == '\n') { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_END_OF_XML_ENTITY); - return JS_FALSE; - } - FastAppendChar(&ts->tokenbuf, (jschar) c); - } - - /* Let length be the number of jschars after the '&', including the ';'. */ - length = PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar) - offset; - bp = ts->tokenbuf.base + offset; - c = d = 0; - ispair = JS_FALSE; - if (length > 2 && bp[1] == '#') { - /* Match a well-formed XML Character Reference. */ - i = 2; - if (length > 3 && JS_TOLOWER(bp[i]) == 'x') { - if (length > 9) /* at most 6 hex digits allowed */ - goto badncr; - while (++i < length) { - digit = bp[i]; - if (!JS7_ISHEX(digit)) - goto badncr; - c = (c << 4) + JS7_UNHEX(digit); - } - } else { - while (i < length) { - digit = bp[i++]; - if (!JS7_ISDEC(digit)) - goto badncr; - c = (c * 10) + JS7_UNDEC(digit); - if (c < 0) - goto badncr; - } - } - - if (0x10000 <= c && c <= 0x10FFFF) { - /* Form a surrogate pair (c, d) -- c is the high surrogate. */ - d = 0xDC00 + (c & 0x3FF); - c = 0xD7C0 + (c >> 10); - ispair = JS_TRUE; - } else { - /* Enforce the http://www.w3.org/TR/REC-xml/#wf-Legalchar WFC. */ - if (c != 0x9 && c != 0xA && c != 0xD && - !(0x20 <= c && c <= 0xD7FF) && - !(0xE000 <= c && c <= 0xFFFD)) { - goto badncr; - } - } - } else { - /* Try to match one of the five XML 1.0 predefined entities. */ - switch (length) { - case 3: - if (bp[2] == 't') { - if (bp[1] == 'l') - c = '<'; - else if (bp[1] == 'g') - c = '>'; - } - break; - case 4: - if (bp[1] == 'a' && bp[2] == 'm' && bp[3] == 'p') - c = '&'; - break; - case 5: - if (bp[3] == 'o') { - if (bp[1] == 'a' && bp[2] == 'p' && bp[4] == 's') - c = '\''; - else if (bp[1] == 'q' && bp[2] == 'u' && bp[4] == 't') - c = '"'; - } - break; - } - if (c == 0) { - msg = JSMSG_UNKNOWN_XML_ENTITY; - goto bad; - } - } - - /* If we matched, retract ts->tokenbuf and store the entity's value. */ - *bp++ = (jschar) c; - if (ispair) - *bp++ = (jschar) d; - *bp = 0; - ts->tokenbuf.ptr = bp; - return JS_TRUE; - -badncr: - msg = JSMSG_BAD_XML_NCR; -bad: - /* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */ - bytes = js_DeflateString(cx, bp + 1, - PTRDIFF(ts->tokenbuf.ptr, bp, jschar) - 1); - if (bytes) { - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - msg, bytes); - JS_free(cx, bytes); - } - return JS_FALSE; -} - -#endif /* JS_HAS_XML_SUPPORT */ - -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->tokens[(ts->cursor + ts->lookahead) & NTOKENS_MASK].type - == TOK_EOL); - ts->flags |= TSF_NEWLINES; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_NEWLINES; - return tt; -} - -/* - * 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 '\\'; -} - -static JSToken * -NewToken(JSTokenStream *ts, ptrdiff_t adjust) -{ - JSToken *tp; - - ts->cursor = (ts->cursor + 1) & NTOKENS_MASK; - tp = &CURRENT_TOKEN(ts); - tp->ptr = ts->linebuf.ptr + adjust; - tp->pos.begin.index = ts->linepos + - PTRDIFF(tp->ptr, ts->linebuf.base, jschar) - - ts->ungetpos; - tp->pos.begin.lineno = tp->pos.end.lineno = (uint16)ts->lineno; - return tp; -} - -JSTokenType -js_GetToken(JSContext *cx, JSTokenStream *ts) -{ - JSTokenType tt; - int32 c, qc; - JSToken *tp; - JSAtom *atom; - JSBool hadUnicodeEscape; - -#define INIT_TOKENBUF() (ts->tokenbuf.ptr = ts->tokenbuf.base) -#define TOKENBUF_LENGTH() PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar) -#define TOKENBUF_OK() STRING_BUFFER_OK(&ts->tokenbuf) -#define TOKENBUF_TO_ATOM() (TOKENBUF_OK() \ - ? js_AtomizeChars(cx, \ - TOKENBUF_BASE(), \ - TOKENBUF_LENGTH(), \ - 0) \ - : NULL) -#define ADD_TO_TOKENBUF(c) FastAppendChar(&ts->tokenbuf, (jschar) (c)) - -/* The following 4 macros should only be used when TOKENBUF_OK() is true. */ -#define TOKENBUF_BASE() (ts->tokenbuf.base) -#define TOKENBUF_CHAR(i) (ts->tokenbuf.base[i]) -#define TRIM_TOKENBUF(i) (ts->tokenbuf.ptr = ts->tokenbuf.base + i) -#define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0) - - /* 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) { - JS_ASSERT(!(ts->flags & TSF_XMLTEXTMODE)); - ts->lookahead--; - ts->cursor = (ts->cursor + 1) & NTOKENS_MASK; - tt = CURRENT_TOKEN(ts).type; - if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES)) - return tt; - } - -#if JS_HAS_XML_SUPPORT - if (ts->flags & TSF_XMLTEXTMODE) { - tt = TOK_XMLSPACE; /* veto if non-space, return TOK_XMLTEXT */ - tp = NewToken(ts, 0); - INIT_TOKENBUF(); - qc = (ts->flags & TSF_XMLONLYMODE) ? '<' : '{'; - - while ((c = GetChar(ts)) != qc && c != '<' && c != EOF) { - if (c == '&' && qc == '<') { - if (!GetXMLEntity(cx, ts)) - goto error; - tt = TOK_XMLTEXT; - continue; - } - - if (!JS_ISXMLSPACE(c)) - tt = TOK_XMLTEXT; - ADD_TO_TOKENBUF(c); - } - UngetChar(ts, c); - - if (TOKENBUF_LENGTH() == 0) { - atom = NULL; - } else { - atom = TOKENBUF_TO_ATOM(); - if (!atom) - goto error; - } - tp->pos.end.lineno = (uint16)ts->lineno; - tp->t_op = JSOP_STRING; - tp->t_atom = atom; - goto out; - } - - if (ts->flags & TSF_XMLTAGMODE) { - tp = NewToken(ts, 0); - c = GetChar(ts); - if (JS_ISXMLSPACE(c)) { - do { - c = GetChar(ts); - } while (JS_ISXMLSPACE(c)); - UngetChar(ts, c); - tt = TOK_XMLSPACE; - goto out; - } - - if (c == EOF) { - tt = TOK_EOF; - goto out; - } - - INIT_TOKENBUF(); - if (JS_ISXMLNSSTART(c)) { - JSBool sawColon = JS_FALSE; - - ADD_TO_TOKENBUF(c); - while ((c = GetChar(ts)) != EOF && JS_ISXMLNAME(c)) { - if (c == ':') { - int nextc; - - if (sawColon || - (nextc = PeekChar(ts), - ((ts->flags & TSF_XMLONLYMODE) || nextc != '{') && - !JS_ISXMLNAME(nextc))) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | - JSREPORT_ERROR, - JSMSG_BAD_XML_QNAME); - goto error; - } - sawColon = JS_TRUE; - } - - ADD_TO_TOKENBUF(c); - } - - UngetChar(ts, c); - atom = TOKENBUF_TO_ATOM(); - if (!atom) - goto error; - tp->t_op = JSOP_STRING; - tp->t_atom = atom; - tt = TOK_XMLNAME; - goto out; - } - - switch (c) { - case '{': - if (ts->flags & TSF_XMLONLYMODE) - goto bad_xml_char; - tt = TOK_LC; - goto out; - - case '=': - tt = TOK_ASSIGN; - goto out; - - case '"': - case '\'': - qc = c; - while ((c = GetChar(ts)) != qc) { - if (c == EOF) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); - goto error; - } - - /* - * XML attribute values are double-quoted when pretty-printed, - * so escape " if it is expressed directly in a single-quoted - * attribute value. - */ - if (c == '"' && !(ts->flags & TSF_XMLONLYMODE)) { - JS_ASSERT(qc == '\''); - js_AppendCString(&ts->tokenbuf, js_quot_entity_str); - continue; - } - - if (c == '&' && (ts->flags & TSF_XMLONLYMODE)) { - if (!GetXMLEntity(cx, ts)) - goto error; - continue; - } - - ADD_TO_TOKENBUF(c); - } - atom = TOKENBUF_TO_ATOM(); - if (!atom) - goto error; - tp->pos.end.lineno = (uint16)ts->lineno; - tp->t_op = JSOP_STRING; - tp->t_atom = atom; - tt = TOK_XMLATTR; - goto out; - - case '>': - tt = TOK_XMLTAGC; - goto out; - - case '/': - if (MatchChar(ts, '>')) { - tt = TOK_XMLPTAGC; - goto out; - } - /* FALL THROUGH */ - - bad_xml_char: - default: - js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, - JSMSG_BAD_XML_CHARACTER); - goto error; - } - /* NOTREACHED */ - } -#endif /* JS_HAS_XML_SUPPORT */ - -retry: - do { - c = GetChar(ts); - if (c == '\n') { - ts->flags &= ~TSF_DIRTYLINE; - if (ts->flags & TSF_NEWLINES) - break; - } - } while (JS_ISSPACE(c)); - - tp = NewToken(ts, -1); - if (c == EOF) { - tt = TOK_EOF; - goto out; - } - - hadUnicodeEscape = JS_FALSE; - if (JS_ISIDSTART(c) || - (c == '\\' && - (c = GetUnicodeEscape(ts), - hadUnicodeEscape = JS_ISIDSTART(c)))) { - INIT_TOKENBUF(); - for (;;) { - ADD_TO_TOKENBUF(c); - 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); - - atom = TOKENBUF_TO_ATOM(); - if (!atom) - goto error; - if (!hadUnicodeEscape && ATOM_KEYWORD(atom)) { - struct keyword *kw; - - JS_ASSERT(!(atom->flags & ATOM_HIDDEN)); - kw = ATOM_KEYWORD(atom); - if (kw->tokentype == TOK_RESERVED) { - char buf[MAX_KEYWORD_LENGTH + 1]; - size_t buflen = sizeof(buf) - 1; - if (!js_DeflateStringToBuffer(cx, TOKENBUF_BASE(), TOKENBUF_LENGTH(), - buf, &buflen)) - goto error; - buf [buflen] = 0; - if (!js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_RESERVED_ID, buf)) { - goto error; - } - } else if (JS_VERSION_IS_ECMA(cx) || - kw->version <= (cx->version & JSVERSION_MASK)) { - tt = kw->tokentype; - tp->t_op = (JSOp) kw->op; - goto out; - } - } - tp->t_op = JSOP_NAME; - tp->t_atom = atom; - tt = TOK_NAME; - goto out; - } - - if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(PeekChar(ts)))) { - jsint radix; - const jschar *endptr; - jsdouble dval; - - radix = 10; - INIT_TOKENBUF(); - - if (c == '0') { - ADD_TO_TOKENBUF(c); - c = GetChar(ts); - if (JS_TOLOWER(c) == 'x') { - ADD_TO_TOKENBUF(c); - 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, - JSREPORT_TS | - JSREPORT_WARNING, - JSMSG_BAD_OCTAL, - c == '8' ? "08" : "09")) { - goto error; - } - radix = 10; - } - } - ADD_TO_TOKENBUF(c); - c = GetChar(ts); - } - - if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) { - if (c == '.') { - do { - ADD_TO_TOKENBUF(c); - c = GetChar(ts); - } while (JS7_ISDEC(c)); - } - if (JS_TOLOWER(c) == 'e') { - ADD_TO_TOKENBUF(c); - c = GetChar(ts); - if (c == '+' || c == '-') { - ADD_TO_TOKENBUF(c); - c = GetChar(ts); - } - if (!JS7_ISDEC(c)) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_MISSING_EXPONENT); - goto error; - } - do { - ADD_TO_TOKENBUF(c); - c = GetChar(ts); - } while (JS7_ISDEC(c)); - } - } - - /* Put back the next char and NUL-terminate tokenbuf for js_strto*. */ - UngetChar(ts, c); - ADD_TO_TOKENBUF(0); - - if (!TOKENBUF_OK()) - goto error; - if (radix == 10) { - if (!js_strtod(cx, TOKENBUF_BASE(), &endptr, &dval)) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_OUT_OF_MEMORY); - goto error; - } - } else { - if (!js_strtointeger(cx, TOKENBUF_BASE(), &endptr, radix, &dval)) { - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_OUT_OF_MEMORY); - goto error; - } - } - tp->t_dval = dval; - tt = TOK_NUMBER; - goto out; - } - - if (c == '"' || c == '\'') { - qc = c; - INIT_TOKENBUF(); - while ((c = GetChar(ts)) != qc) { - if (c == '\n' || c == EOF) { - UngetChar(ts, c); - js_ReportCompileErrorNumber(cx, ts, - JSREPORT_TS | JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); - goto 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') { - int32 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' && JS_VERSION_IS_ECMA(cx)) { - /* ECMA follows C by removing escaped newlines. */ - continue; - } - break; - } - } - ADD_TO_TOKENBUF(c); - } - atom = TOKENBUF_TO_ATOM(); - if (!atom) - goto error; - tp->pos.end.lineno = (uint16)ts->lineno; - tp->t_op = JSOP_STRING; - tp->t_atom = atom; - tt = TOK_STRING; - goto out; - } - - switch (c) { - case '\n': tt = TOK_EOL; goto eol_out; - case ';': tt = TOK_SEMI; break; - case '[': tt = TOK_LB; break; - case ']': tt = TOK_RB; break; - case '{': tt = TOK_LC; break; - case '}': tt = TOK_RC; break; - case '(': tt = TOK_LP; break; - case ')': tt = TOK_RP; break; - case ',': tt = TOK_COMMA; break; - case '?': tt = TOK_HOOK; break; - - case '.': -#if JS_HAS_XML_SUPPORT - if (MatchChar(ts, c)) - tt = TOK_DBLDOT; - else -#endif - tt = TOK_DOT; - break; - - case ':': -#if JS_HAS_XML_SUPPORT - if (MatchChar(ts, c)) { - tt = TOK_DBLCOLON; - break; - } -#endif - /* - * Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an - * object initializer, likewise for setter. - */ - tp->t_op = JSOP_NOP; - tt = TOK_COLON; - break; - - case '|': - if (MatchChar(ts, c)) { - tt = TOK_OR; - } else if (MatchChar(ts, '=')) { - tp->t_op = JSOP_BITOR; - tt = TOK_ASSIGN; - } else { - tt = TOK_BITOR; - } - break; - - case '^': - if (MatchChar(ts, '=')) { - tp->t_op = JSOP_BITXOR; - tt = TOK_ASSIGN; - } else { - tt = TOK_BITXOR; - } - break; - - case '&': - if (MatchChar(ts, c)) { - tt = TOK_AND; - } else if (MatchChar(ts, '=')) { - tp->t_op = JSOP_BITAND; - tt = TOK_ASSIGN; - } else { - tt = 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 - tt = TOK_EQOP; - } else { - tp->t_op = JSOP_NOP; - tt = 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 - tt = TOK_EQOP; - } else { - tp->t_op = JSOP_NOT; - tt = TOK_UNARYOP; - } - break; - -#if JS_HAS_XML_SUPPORT - case '@': - tt = TOK_AT; - break; -#endif - - case '<': -#if JS_HAS_XML_SUPPORT - /* - * After much testing, it's clear that Postel's advice to protocol - * designers ("be liberal in what you accept, and conservative in what - * you send") invites a natural-law repercussion for JS as "protocol": - * - * "If you are liberal in what you accept, others will utterly fail to - * be conservative in what they send." - * - * Which means you will get within every //-style comment unless we have to. So we set - * TSF_IN_HTML_COMMENT when a either on a clean line, or - * only if (ts->flags & TSF_IN_HTML_COMMENT), in a //-style comment. - * - * This still works as before given a malformed comment hiding hack such as: - * - * - * - * It does not cope with malformed comment hiding hacks where --> is hidden - * by C-style comments, or on a dirty line. Such cases are already broken. - */ -#define TSF_IN_HTML_COMMENT 0x2000 - -/* 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); - -extern JS_FRIEND_API(int) -js_fgets(char *buf, int size, FILE *file); - -/* - * 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, void *handle, uintN flags, - uintN errorNumber, ...); - -extern JSBool -js_ReportCompileErrorNumberUC(JSContext *cx, void *handle, uintN flags, - uintN errorNumber, ...); - -/* Steal some JSREPORT_* bits (see jsapi.h) to tell handle's type. */ -#define JSREPORT_HANDLE 0x300 -#define JSREPORT_TS 0x000 -#define JSREPORT_CG 0x100 -#define JSREPORT_PN 0x200 - -/* - * 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 deleted file mode 100644 index 4f9512387..000000000 --- a/src/dom/js/jsscope.c +++ /dev/null @@ -1,1702 +0,0 @@ -/* -*- 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 -#include -#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(JSContext *cx, JSScope *scope, JSBool report) -{ - 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) { - if (report) - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - /* Racy update after calloc, to help keep the GC self-scheduled well. */ - cx->runtime->gcMallocBytes += JS_BIT(sizeLog2) * sizeof(JSScopeProperty *); - - 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; - scope->dswIndex = 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 DUMP_SCOPE_STATS -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; - - /* Treat the above calloc as a JS_malloc, to match CreateScopeTable. */ - cx->runtime->gcMallocBytes += nbytes; - - /* 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, PropTreeKidsChunk *sweptChunk) -{ - 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); - - if (sweptChunk) { - chunk = sweptChunk; - } else { - 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, NULL)) - 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(cx, scope, JS_TRUE)) - 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(cx, scope, JS_FALSE); - } - - 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 DUMP_SCOPE_STATS - 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(cx, scope, JS_TRUE)) - 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 DUMP_SCOPE_STATS - -#include -#include - -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; -} - -#include "jsprf.h" - -static void -DumpSubtree(JSScopeProperty *sprop, int level, FILE *fp) -{ - char buf[10]; - JSScopeProperty *kids, *kid; - PropTreeKidsChunk *chunk; - uintN i; - - fprintf(fp, "%*sid %s g/s %p/%p slot %lu attrs %x flags %x shortid %d\n", - level, "", - JSID_IS_ATOM(sprop->id) - ? JS_GetStringBytes(ATOM_TO_STRING(JSID_TO_ATOM(sprop->id))) - : JSID_IS_OBJECT(sprop->id) - ? js_ValueToPrintableString(cx, OBJECT_JSID_TO_JSVAL(sprop->id)) - : (JS_snprintf(buf, sizeof buf, "%ld", JSVAL_TO_INT(sprop->id)), - buf) - (void *) sprop->getter, (void *) sprop->setter, - (unsigned long) sprop->slot, sprop->attrs, sprop->flags, - sprop->shortid); - kids = sprop->kids; - if (kids) { - ++level; - 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); - DumpSubtree(kid, level, fp); - } - } while ((chunk = chunk->next) != NULL); - } else { - kid = kids; - DumpSubtree(kid, level, fp); - } - } -} - -#endif /* DUMP_SCOPE_STATS */ - -void -js_SweepScopeProperties(JSRuntime *rt) -{ - JSArena **ap, *a; - JSScopeProperty *limit, *sprop, *parent, *kids, *kid; - uintN liveCount; - PropTreeKidsChunk *chunk, *nextChunk; - uintN i; - -#ifdef DUMP_SCOPE_STATS - 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.0, var = 0.0, sigma = 0.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.0) ? sqrt(var) : 0.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. - * InsertPropertyTreeChild can potentially fail for two reasons: - * - * 1. If parent is null, insertion into the root property hash - * table may fail. We are forced to leave the kid out of the - * table (as can already happen with duplicates) but ensure - * that the kid's parent pointer is set to null. - * - * 2. If parent is non-null, allocation of a new KidsChunk can - * fail. To prevent this from happening, we allow sprops's own - * chunks to be reused by the grandparent, which removes the - * need for InsertPropertyTreeChild to malloc a new KidsChunk. - * - * We also require the grandparent to have either no kids or else - * chunky kids. A single non-chunky kid would force a new chunk to - * be malloced in some cases (if sprop had a single non-chunky - * kid, or a multiple of MAX_KIDS_PER_CHUNK kids). Note that - * RemovePropertyTreeChild never converts a single entry chunky - * kid back to a non-chunky kid, so we are assured of correct - * behaviour. - */ - kids = sprop->kids; - if (kids) { - sprop->kids = NULL; - parent = sprop->parent; - /* Validate that grandparent has no kids or chunky kids. */ - JS_ASSERT(!parent || !parent->kids || - KIDS_IS_CHUNKY(parent->kids)); - if (KIDS_IS_CHUNKY(kids)) { - chunk = KIDS_TO_CHUNK(kids); - do { - nextChunk = chunk->next; - chunk->next = NULL; - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - kid = chunk->kids[i]; - if (!kid) - break; - JS_ASSERT(kid->parent == sprop); - - /* - * Clear a space in the kids array for possible - * re-use by InsertPropertyTreeChild. - */ - chunk->kids[i] = NULL; - if (!InsertPropertyTreeChild(rt, parent, kid, - chunk)) { - /* - * This can happen only if we failed to add an - * entry to the root property hash table. - */ - JS_ASSERT(!parent); - kid->parent = NULL; - } - } - if (!chunk->kids[0]) { - /* The chunk wasn't reused so we can free it */ - DestroyPropTreeKidsChunk(rt, chunk); - } - } while ((chunk = nextChunk) != NULL); - } else { - kid = kids; - if (!InsertPropertyTreeChild(rt, parent, kid, NULL)) { - /* - * The removal of sprop should have left a free space - * for kid to be inserted into parent, unless the root - * hash table was shrunk. In this case we allow for - * failure only when parent is null. - */ - JS_ASSERT(!parent); - kid->parent = NULL; - } - } - } - - /* 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 DUMP_SCOPE_STATS - livePropCapacity += limit - (JSScopeProperty *) a->base; - totalLiveCount += liveCount; -#endif - ap = &a->next; - } - } - -#ifdef DUMP_SCOPE_STATS - fprintf(logfp, " arenautil %g%%\n", - (totalLiveCount * 100.0) / livePropCapacity); - fflush(logfp); -#endif - -#ifdef DUMP_PROPERTY_TREE - { - FILE *dumpfp = fopen("/tmp/proptree.dump", "w"); - if (dumpfp) { - JSPropertyTreeEntry *pte, *end; - - pte = (JSPropertyTreeEntry *) rt->propertyTreeHash.entryStore; - end = pte + JS_DHASH_TABLE_SIZE(&rt->propertyTreeHash); - while (pte < end) { - if (pte->child) - DumpSubtree(pte->child, 0, dumpfp); - pte++; - } - fclose(dumpfp); - } - } -#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 deleted file mode 100644 index 0f8a837c0..000000000 --- a/src/dom/js/jsscope.h +++ /dev/null @@ -1,394 +0,0 @@ -/* -*- 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 */ - uint8 flags; /* flags, see below */ - int8 hashShift; /* multiplicative hash shift */ - uint16 dswIndex; /* Deutsch-Schorr-Waite scaled index */ - 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 -#define SPROP_IS_HIDDEN 0x10 /* a normally-hidden property, - e.g., function arg or var */ - -/* - * 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_HAS_STUB_GETTER(sprop) (!(sprop)->getter) -#define SPROP_HAS_STUB_SETTER(sprop) (!(sprop)->setter) - -#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) (JSID_IS_ATOM(id) ? ATOM_JSID_TO_JSVAL(id) : \ - JSID_IS_OBJECT(id) ? OBJECT_JSID_TO_JSVAL(id) : \ - (jsval)(id)) -#define HASH_ID(id) (JSID_IS_ATOM(id) ? JSID_TO_ATOM(id)->number : \ - JSID_IS_OBJECT(id) ? (jsatomid) JSID_CLRTAG(id) : \ - (jsatomid) JSID_TO_INT(id)) - -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 deleted file mode 100644 index 6fc92de93..000000000 --- a/src/dom/js/jsscript.c +++ /dev/null @@ -1,1490 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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 -#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 - -static const char js_script_exec[] = "Script.prototype.exec"; -static const char js_script_compile[] = "Script.prototype.compile"; - -#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; - JSStackFrame *fp, *caller; - JSString *str; - 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; - - /* XXX thread safety was completely neglected in this function... */ - oldscript = (JSScript *) JS_GetPrivate(cx, obj); - if (oldscript) { - for (fp = cx->fp; fp; fp = fp->down) { - if (fp->script == oldscript) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_SELF_MODIFYING_SCRIPT); - return JS_FALSE; - } - } - } - - /* Otherwise, the first arg is the script source to compile. */ - str = js_ValueToString(cx, argv[0]); - if (!str) - return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); - - /* 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; - } - - /* Ensure we compile this script with the right (inner) principals. */ - scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile); - if (!scopeobj) - return JS_FALSE; - - /* - * Compile the new script using the caller's scope chain, a la eval(). - * Unlike jsobj.c:obj_eval, however, we do not set JSFRAME_EVAL in fp's - * flags, because compilation is here separated from execution, and the - * run-time scope chain may not match the compile-time. JSFRAME_EVAL is - * tested in jsemit.c and jsscan.c to optimize based on identity of run- - * and compile-time scope. - */ - fp->flags |= JSFRAME_SCRIPT_OBJECT; - 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. */ - 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; - JSPrincipals *principals; - - 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; - } - } - - scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec); - if (!scopeobj) - return JS_FALSE; - - /* Belt-and-braces: check that this script object has access to scopeobj. */ - principals = script->principals; - if (!js_CheckPrincipalsAccess(cx, scopeobj, principals, js_script_exec)) - return JS_FALSE; - - 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); - JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN); - version = (uint32)script->version | (script->numGlobalVars << 16); - 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 & 0xffff); - script->numGlobalVars = (uint16) (version >> 16); - - /* 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 magic < _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); - memset(script->trynotes, 0, ntrynotes * sizeof(JSTryNote)); - } - } - } - - 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; - argv[0] = STRING_TO_JSVAL(str); - - /* 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; - - /* - * script_compile does not use rval to root its temporaries - * so we can use it to root obj. - */ - *rval = OBJECT_TO_JSVAL(obj); - } - 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. - */ -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 */ - uint32 flags; /* user-defined filename prefix flags */ - JSPackedBool mark; /* GC mark flag */ - char filename[3]; /* two or more bytes, NUL-terminated */ -} ScriptFilenameEntry; - -JS_STATIC_DLL_CALLBACK(JSHashEntry *) -js_alloc_sftbl_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_sftbl_entry(void *priv, JSHashEntry *he, uintN flag) -{ - if (flag != HT_FREE_ENTRY) - return; - free(he); -} - -static JSHashAllocOps sftbl_alloc_ops = { - js_alloc_table_space, js_free_table_space, - js_alloc_sftbl_entry, js_free_sftbl_entry -}; - -JSBool -js_InitRuntimeScriptState(JSRuntime *rt) -{ -#ifdef JS_THREADSAFE - JS_ASSERT(!rt->scriptFilenameTableLock); - rt->scriptFilenameTableLock = JS_NEW_LOCK(); - if (!rt->scriptFilenameTableLock) - return JS_FALSE; -#endif - JS_ASSERT(!rt->scriptFilenameTable); - rt->scriptFilenameTable = - JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL, - &sftbl_alloc_ops, NULL); - if (!rt->scriptFilenameTable) { - js_FinishRuntimeScriptState(rt); /* free lock if threadsafe */ - return JS_FALSE; - } - JS_INIT_CLIST(&rt->scriptFilenamePrefixes); - return JS_TRUE; -} - -typedef struct ScriptFilenamePrefix { - JSCList links; /* circular list linkage for easy deletion */ - const char *name; /* pointer to pinned ScriptFilenameEntry string */ - size_t length; /* prefix string length, precomputed */ - uint32 flags; /* user-defined flags to inherit from this prefix */ -} ScriptFilenamePrefix; - -void -js_FinishRuntimeScriptState(JSRuntime *rt) -{ - if (rt->scriptFilenameTable) { - JS_HashTableDestroy(rt->scriptFilenameTable); - rt->scriptFilenameTable = NULL; - } -#ifdef JS_THREADSAFE - if (rt->scriptFilenameTableLock) { - JS_DESTROY_LOCK(rt->scriptFilenameTableLock); - rt->scriptFilenameTableLock = NULL; - } -#endif -} - -void -js_FreeRuntimeScriptState(JSRuntime *rt) -{ - ScriptFilenamePrefix *sfp; - - while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) { - sfp = (ScriptFilenamePrefix *) rt->scriptFilenamePrefixes.next; - JS_REMOVE_LINK(&sfp->links); - free(sfp); - } - js_FinishRuntimeScriptState(rt); -} - -#ifdef DEBUG_brendan -size_t sftbl_savings = 0; -#endif - -static ScriptFilenameEntry * -SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags) -{ - JSHashTable *table; - JSHashNumber hash; - JSHashEntry **hep; - ScriptFilenameEntry *sfe; - size_t length; - JSCList *head, *link; - ScriptFilenamePrefix *sfp; - - table = rt->scriptFilenameTable; - hash = JS_HashString(filename); - hep = JS_HashTableRawLookup(table, hash, filename); - sfe = (ScriptFilenameEntry *) *hep; -#ifdef DEBUG_brendan - if (sfe) - sftbl_savings += strlen(sfe->filename); -#endif - - if (!sfe) { - sfe = (ScriptFilenameEntry *) - JS_HashTableRawAdd(table, hep, hash, filename, NULL); - if (!sfe) - return NULL; - sfe->key = strcpy(sfe->filename, filename); - sfe->flags = 0; - sfe->mark = JS_FALSE; - } - - /* If saving a prefix, add it to the set in rt->scriptFilenamePrefixes. */ - if (flags != 0) { - /* Search in case filename was saved already; we must be idempotent. */ - sfp = NULL; - length = strlen(filename); - for (head = link = &rt->scriptFilenamePrefixes; - link->next != head; - link = link->next) { - /* Lag link behind sfp to insert in non-increasing length order. */ - sfp = (ScriptFilenamePrefix *) link->next; - if (!strcmp(sfp->name, filename)) - break; - if (sfp->length <= length) { - sfp = NULL; - break; - } - sfp = NULL; - } - - if (!sfp) { - /* No such prefix: add one now. */ - sfp = (ScriptFilenamePrefix *) malloc(sizeof(ScriptFilenamePrefix)); - if (!sfp) - return NULL; - JS_INSERT_AFTER(&sfp->links, link); - sfp->name = sfe->filename; - sfp->length = length; - sfp->flags = 0; - } - - /* - * Accumulate flags in both sfe and sfp: sfe for later access from the - * JS_GetScriptedCallerFilenameFlags debug-API, and sfp so that longer - * filename entries can inherit by prefix. - */ - sfe->flags |= flags; - sfp->flags |= flags; - } - - return sfe; -} - -const char * -js_SaveScriptFilename(JSContext *cx, const char *filename) -{ - JSRuntime *rt; - ScriptFilenameEntry *sfe; - JSCList *head, *link; - ScriptFilenamePrefix *sfp; - - rt = cx->runtime; - JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); - sfe = SaveScriptFilename(rt, filename, 0); - if (!sfe) { - JS_RELEASE_LOCK(rt->scriptFilenameTableLock); - JS_ReportOutOfMemory(cx); - return NULL; - } - - /* - * Try to inherit flags by prefix. We assume there won't be more than a - * few (dozen! ;-) prefixes, so linear search is tolerable. - * XXXbe every time I've assumed that in the JS engine, I've been wrong! - */ - for (head = &rt->scriptFilenamePrefixes, link = head->next; - link != head; - link = link->next) { - sfp = (ScriptFilenamePrefix *) link; - if (!strncmp(sfp->name, filename, sfp->length)) { - sfe->flags |= sfp->flags; - break; - } - } - JS_RELEASE_LOCK(rt->scriptFilenameTableLock); - return sfe->filename; -} - -const char * -js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags) -{ - ScriptFilenameEntry *sfe; - - /* This may be called very early, via the jsdbgapi.h entry point. */ - if (!rt->scriptFilenameTable && !js_InitRuntimeScriptState(rt)) - return NULL; - - JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); - sfe = SaveScriptFilename(rt, filename, flags); - JS_RELEASE_LOCK(rt->scriptFilenameTableLock); - if (!sfe) - return NULL; - - return sfe->filename; -} - -/* - * Back up from a saved filename by its offset within its hash table entry. - */ -#define FILENAME_TO_SFE(fn) \ - ((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename))) - -/* - * 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. - */ -#define ASSERT_VALID_SFE(sfe) JS_ASSERT((sfe)->key == (sfe)->filename) - -uint32 -js_GetScriptFilenameFlags(const char *filename) -{ - ScriptFilenameEntry *sfe; - - sfe = FILENAME_TO_SFE(filename); - ASSERT_VALID_SFE(sfe); - return sfe->flags; -} - -void -js_MarkScriptFilename(const char *filename) -{ - ScriptFilenameEntry *sfe; - - sfe = FILENAME_TO_SFE(filename); - ASSERT_VALID_SFE(sfe); - sfe->mark = JS_TRUE; -} - -JS_STATIC_DLL_CALLBACK(intN) -js_script_filename_marker(JSHashEntry *he, intN i, void *arg) -{ - ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he; - - sfe->mark = JS_TRUE; - return HT_ENUMERATE_NEXT; -} - -void -js_MarkScriptFilenames(JSRuntime *rt, uintN gcflags) -{ - JSCList *head, *link; - ScriptFilenamePrefix *sfp; - - if (gcflags & GC_KEEP_ATOMS) { - JS_HashTableEnumerateEntries(rt->scriptFilenameTable, - js_script_filename_marker, - rt); - } - for (head = &rt->scriptFilenamePrefixes, link = head->next; - link != head; - link = link->next) { - sfp = (ScriptFilenamePrefix *) link; - js_MarkScriptFilename(sfp->name); - } -} - -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(rt->scriptFilenameTable, - js_script_filename_sweeper, - rt); -#ifdef DEBUG_notme - printf("script filename table savings so far: %u\n", sftbl_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); - memset(script->trynotes, 0, ntrynotes * sizeof(JSTryNote)); - } - 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)); - script->numGlobalVars = cg->treeContext.numGlobalVars; - 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) { - JS_KEEP_ATOMS(rt); - hook(cx, script->filename, script->lineno, script, fun, - rt->newScriptHookData); - JS_UNKEEP_ATOMS(rt); - } -} - -JS_FRIEND_API(void) -js_CallDestroyScriptHook(JSContext *cx, JSScript *script) -{ - JSRuntime *rt; - JSDestroyScriptHook hook; - - rt = cx->runtime; - hook = rt->destroyScriptHook; - if (hook) - hook(cx, script, rt->destroyScriptHookData); -} - -void -js_DestroyScript(JSContext *cx, JSScript *script) -{ - js_CallDestroyScriptHook(cx, script); - - 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)); - JS_ASSERT(fun->interpreted); - return fun->u.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; -} - -/* The line number limit is the same as the jssrcnote offset limit. */ -#define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16) - -jsbytecode * -js_LineNumberToPC(JSScript *script, uintN target) -{ - ptrdiff_t offset, best; - uintN lineno, bestdiff, diff; - jssrcnote *sn; - JSSrcNoteType type; - - offset = 0; - best = -1; - lineno = script->lineno; - bestdiff = SN_LINE_LIMIT; - for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - if (lineno == target) - goto out; - if (lineno > target) { - diff = lineno - target; - if (diff < bestdiff) { - bestdiff = diff; - best = offset; - } - } - 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++; - } - } - if (best >= 0) - offset = best; -out: - return script->code + offset; -} - -JS_FRIEND_API(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 deleted file mode 100644 index 77f59ed75..000000000 --- a/src/dom/js/jsscript.h +++ /dev/null @@ -1,209 +0,0 @@ -/* -*- 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 main entry point - * 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 */ - uint16 version; /* JS version under which script was compiled */ - uint16 numGlobalVars; /* declared global var/const/function count */ - 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); - -/* - * On first new context in rt, initialize script runtime state, specifically - * the script filename table and its lock. - */ -extern JSBool -js_InitRuntimeScriptState(JSRuntime *rt); - -/* - * On last context destroy for rt, if script filenames are all GC'd, free the - * script filename table and its lock. - */ -extern void -js_FinishRuntimeScriptState(JSRuntime *rt); - -/* - * On JS_DestroyRuntime(rt), forcibly free script filename prefixes and any - * script filename table entries that have not been GC'd, the latter using - * js_FinishRuntimeScriptState. - * - * This allows script filename prefixes to outlive any context in rt. - */ -extern void -js_FreeRuntimeScriptState(JSRuntime *rt); - -extern const char * -js_SaveScriptFilename(JSContext *cx, const char *filename); - -extern const char * -js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags); - -extern uint32 -js_GetScriptFilenameFlags(const char *filename); - -extern void -js_MarkScriptFilename(const char *filename); - -extern void -js_MarkScriptFilenames(JSRuntime *rt, uintN gcflags); - -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 JS_FRIEND_API(void) -js_CallDestroyScriptHook(JSContext *cx, JSScript *script); - -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 JS_FRIEND_API(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 deleted file mode 100644 index 4b811ac01..000000000 --- a/src/dom/js/jsshell.msg +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- 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, "") -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 deleted file mode 100644 index addaa88ff..000000000 --- a/src/dom/js/jsstddef.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- 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 - - diff --git a/src/dom/js/jsstr.c b/src/dom/js/jsstr.c deleted file mode 100644 index 5e0bafd3b..000000000 --- a/src/dom/js/jsstr.c +++ /dev/null @@ -1,4868 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: - * - * ***** 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 -#include -#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 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 */ - } - - /* - * This overflow test works because newlength is incremented by at - * most 5 on each iteration. - */ - if (newlength < length) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - } - - if (newlength >= ~(size_t)0 / sizeof(jschar)) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - 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; - - /* - * Call js_ValueToString because getters and setters can be invoked on - * objects of different class, unlike enumerate, resolve, and the other - * class hooks. - */ - 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; - - /* Avoid infinite recursion via js_obj_toSource (see bug 271477). */ - if (JS_VERSION_IS_1_2(cx)) - return JS_TRUE; - - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - return JS_TRUE; - cx->newborn[GCX_STRING] = (JSGCThing *) str; - - 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_JSID(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, uintN flags, - JSObject **objp) -{ - JSString *str, *str1; - jsint slot; - - if (!JSVAL_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING)) - return JS_TRUE; - - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - return JS_TRUE; - cx->newborn[GCX_STRING] = (JSGCThing *) str; - - 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_JSID(slot), - STRING_TO_JSVAL(str1), NULL, NULL, - STRING_ELEMENT_ATTRS, NULL)) { - return JS_FALSE; - } - *objp = obj; - } - return JS_TRUE; -} - -JSClass js_StringClass = { - js_String_str, - JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE, - JS_PropertyStub, JS_PropertyStub, str_getProperty, JS_PropertyStub, - str_enumerate, (JSResolveOp)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; - argv[-1] = STRING_TO_JSVAL(str); - - 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, &js_StringClass, 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(", js_StringClass.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, &js_StringClass, 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, &js_StringClass, 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 (!JS_VERSION_IS_1_2(cx)) { - /* 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; - argv[-1] = STRING_TO_JSVAL(str); - - 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; - argv[-1] = STRING_TO_JSVAL(str); - 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; - argv[-1] = STRING_TO_JSVAL(str); - - 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; - argv[-1] = STRING_TO_JSVAL(str); - 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) { - argv[0] = STRING_TO_JSVAL(thatStr); - 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) - i = textlen; - 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; - } - /* From here on, all control flow must reach the matching DROP. */ - data->regexp = re; - HOLD_REGEXP(cx, 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); - } else { - ok = JS_TRUE; - } - if (ok) { - 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. - */ - JSStackFrame *fp = cx->fp->down; - - /* Skip Function.prototype.call and .apply frames. */ - while (fp && !fp->pc) { - JS_ASSERT(!fp->script); - fp = fp->down; - } - - /* Assume a full array result is required, then prove otherwise. */ - test = JS_FALSE; - if (fp) { - JS_ASSERT(*fp->pc == JSOP_CALL || *fp->pc == JSOP_NEW); - JS_ASSERT(js_CodeSpec[*fp->pc].length == 3); - switch (fp->pc[3]) { - case JSOP_POP: - case JSOP_IFEQ: - case JSOP_IFNE: - case JSOP_IFEQX: - case JSOP_IFNEX: - test = JS_TRUE; - break; - default:; - } - } - } - ok = js_ExecuteRegExp(cx, re, str, &index, test, rval); - } - - DROP_REGEXP(cx, re); - 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_JSID(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, jschar *ep, ReplaceData *rdata, - size_t *skip) -{ - JSVersion version; - 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. - */ - version = cx->version & JSVERSION_MASK; - if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4) { - if (dp > JSSTRING_CHARS(rdata->repstr) && dp[-1] == '\\') - return NULL; - } - - /* If there is only a dollar, bail now */ - if (dp + 1 >= ep) - return NULL; - - /* Interpret all Perl match-induced dollar variables. */ - res = &cx->regExpStatics; - dc = dp[1]; - if (JS7_ISDEC(dc)) { - if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4) { - if (dc == '0') - return NULL; - - /* Check for overflow to avoid gobbling arbitrary decimal digits. */ - num = 0; - cp = dp; - while (++cp < ep && (dc = *cp, 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; - if (cp < ep && (dc = *cp, 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 (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 regExpStatics from the current regexp, since they may be - * clobbered by a RegExp usage in the lambda function. Note that all - * members of JSRegExpStatics are JSSubStrings, so not GC roots, save - * input, which is rooted otherwise via argv[-1] in str_replace. - */ - JSRegExpStatics save = cx->regExpStatics; - JSBool freeMoreParens = JS_FALSE; - - /* - * 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]); - - /* - * We need to clear moreParens in the top-of-stack cx->regExpStatics - * to it won't be possibly realloc'ed, leaving the bottom-of-stack - * moreParens pointing to freed memory. - */ - cx->regExpStatics.moreParens = NULL; - freeMoreParens = JS_TRUE; - -#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); - if (freeMoreParens) - JS_free(cx, cx->regExpStatics.moreParens); - cx->regExpStatics = save; - 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, ep, 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, ep, 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; - JSVersion version; - 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; - version = cx->version & JSVERSION_MASK; - if (version == JSVERSION_DEFAULT || 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 (JS_VERSION_IS_1_2(cx) && - !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 (JS_VERSION_IS_1_2(cx)) { - sep->length = 1; - return i; - } - return -1; - } - i++; - goto again; - } - if ((size_t)i == length) { - /* - * If there was a trivial zero-length match at the end of the - * split, then we shouldn't output the matched string at the end - * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15. - */ - sep->chars = NULL; - } - } - 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 (!JS_VERSION_IS_ECMA(cx) && 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 (JS_VERSION_IS_1_2(cx)) { - 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 (!JS_VERSION_IS_ECMA(cx)) { - /* - * 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; - 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 = 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, JSString *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; /* '' */ - parlen = 0; /* Avoid warning. */ - if (param) { - parlen = JSSTRING_LENGTH(param); - taglen += 2 + parlen + 1; /* '="param"' */ - } - endlen = strlen(end); - taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1; /* 'str' */ - - if (taglen >= ~(size_t)0 / sizeof(jschar)) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - 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], JSSTRING_CHARS(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, 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,JSFUN_GENERIC_NATIVE,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,JSFUN_GENERIC_NATIVE,0}, - {"toLowerCase", str_toLowerCase, 0,JSFUN_GENERIC_NATIVE,0}, - {"toUpperCase", str_toUpperCase, 0,JSFUN_GENERIC_NATIVE,0}, - {"charAt", str_charAt, 1,JSFUN_GENERIC_NATIVE,0}, - {"charCodeAt", str_charCodeAt, 1,JSFUN_GENERIC_NATIVE,0}, - {"indexOf", str_indexOf, 1,JSFUN_GENERIC_NATIVE,0}, - {"lastIndexOf", str_lastIndexOf, 1,JSFUN_GENERIC_NATIVE,0}, - {"toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE,0}, - {"toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE,0}, - {"localeCompare", str_localeCompare, 1,JSFUN_GENERIC_NATIVE,0}, - - /* Perl-ish methods (search is actually Python-esque). */ -#if JS_HAS_REGEXPS - {"match", str_match, 1,JSFUN_GENERIC_NATIVE,2}, - {"search", str_search, 1,JSFUN_GENERIC_NATIVE,0}, - {"replace", str_replace, 2,JSFUN_GENERIC_NATIVE,0}, - {"split", str_split, 2,JSFUN_GENERIC_NATIVE,0}, -#endif -#if JS_HAS_PERL_SUBSTR - {"substr", str_substr, 2,JSFUN_GENERIC_NATIVE,0}, -#endif - - /* Python-esque sequence methods. */ -#if JS_HAS_SEQUENCE_OPS - {"concat", str_concat, 0,JSFUN_GENERIC_NATIVE,0}, - {"slice", str_slice, 0,JSFUN_GENERIC_NATIVE,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; - argv[0] = STRING_TO_JSVAL(str); - } 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; - JSAtom *atom; - - 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. */ - atom = js_AtomizeString(cx, empty, ATOM_PINNED); - if (!atom) - return JS_FALSE; - - rt->emptyString = empty; - rt->atomState.emptyAtom = atom; - 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, &js_StringClass, 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_NewGCThing(cx, gcflag | GCX_STRING, sizeof(JSString)); - 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 == 0 && length == JSSTRING_LENGTH(base)) - return base; - - if (start > JSSTRDEP_START_MASK || - (start != 0 && length > JSSTRDEP_LENGTH_MASK)) { - return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length, - gcflag); - } - - ds = (JSDependentString *) - js_NewGCThing(cx, gcflag | GCX_MUTABLE_STRING, sizeof(JSString)); - 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 - -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)JS_PTR_TO_UINT32(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, &js_StringClass, NULL, NULL); - if (!obj) - return NULL; - OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str)); - return obj; -} - -JS_FRIEND_API(const char *) -js_ValueToPrintableString(JSContext *cx, jsval v) -{ - JSString *str; - const char *bytes; - - str = js_ValueToString(cx, v); - if (!str) - return NULL; - str = js_QuoteString(cx, str, 0); - if (!str) - return NULL; - bytes = js_GetStringBytes(str); - if (!bytes) - JS_ReportOutOfMemory(cx); - return bytes; -} - -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) -{ - JSTempValueRooter tvr; - JSString *str; - - 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); - } - return js_ValueToString(cx, v); - } - - JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); - if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), - cx->runtime->atomState.toSourceAtom, - 0, NULL, &tvr.u.value)) { - str = NULL; - } else { - str = js_ValueToString(cx, tvr.u.value); - } - JS_POP_TEMP_ROOT(cx, &tvr); - return str; -} - -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; -} - -#ifdef JS_C_STRINGS_ARE_UTF8 - -jschar * -js_InflateString(JSContext *cx, const char *bytes, size_t *length) -{ - jschar *chars = NULL; - size_t dstlen = 0; - - if (!js_InflateStringToBuffer(cx, bytes, *length, NULL, &dstlen)) - return NULL; - chars = (jschar *) JS_malloc(cx, (dstlen + 1) * sizeof (jschar)); - if (!chars) - return NULL; - js_InflateStringToBuffer(cx, bytes, *length, chars, &dstlen); - chars[dstlen] = 0; - *length = dstlen; - 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 size = 0; - char *bytes = NULL; - if (!js_DeflateStringToBuffer(cx, chars, length, NULL, &size)) - return NULL; - bytes = (char *) (cx ? JS_malloc(cx, size+1) : malloc(size+1)); - if (!bytes) - return NULL; - js_DeflateStringToBuffer(cx, chars, length, bytes, &size); - bytes[size] = 0; - return bytes; -} - -JSBool -js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen, - char *dst, size_t *dstlenp) -{ - size_t i, utf8Len, dstlen = *dstlenp, origDstlen = dstlen; - jschar c, c2; - uint32 v; - uint8 utf8buf[6]; - - if (!dst) - dstlen = origDstlen = (size_t) -1; - - while (srclen) { - c = *src++; - srclen--; - if ((c >= 0xDC00) && (c <= 0xDFFF)) - goto badSurrogate; - if (c < 0xD800 || c > 0xDBFF) { - v = c; - } else { - if (srclen < 1) - goto bufferTooSmall; - c2 = *src++; - srclen--; - if ((c2 < 0xDC00) || (c2 > 0xDFFF)) { - c = c2; - goto badSurrogate; - } - v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; - } - if (v < 0x0080) { - /* no encoding necessary - performance hack */ - if (!dstlen) - goto bufferTooSmall; - if (dst) - *dst++ = (char) v; - utf8Len = 1; - } else { - utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v); - if (utf8Len > dstlen) - goto bufferTooSmall; - if (dst) { - for (i = 0; i < utf8Len; i++) - *dst++ = (char) utf8buf[i]; - } - } - dstlen -= utf8Len; - } - *dstlenp = (origDstlen - dstlen); - return JS_TRUE; - -badSurrogate: - *dstlenp = (origDstlen - dstlen); - if (cx) { - char buffer[10]; - JS_snprintf(buffer, 10, "0x%x", c); - JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, - js_GetErrorMessage, NULL, - JSMSG_BAD_SURROGATE_CHAR, - buffer); - } - return JS_FALSE; - -bufferTooSmall: - *dstlenp = (origDstlen - dstlen); - if (cx) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BUFFER_TOO_SMALL); - } - return JS_FALSE; -} - -JSBool -js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen, - jschar *dst, size_t *dstlenp) -{ - uint32 v; - size_t offset = 0, j, n, dstlen = *dstlenp, origDstlen = dstlen; - - if (!dst) - dstlen = origDstlen = (size_t) -1; - - while (srclen) { - v = (uint8) *src; - n = 1; - if (v & 0x80) { - while (v & (0x80 >> n)) - n++; - if (n > srclen) - goto bufferTooSmall; - if (n == 1 || n > 6) - goto badCharacter; - for (j = 1; j < n; j++) { - if ((src[j] & 0xC0) != 0x80) - goto badCharacter; - } - v = Utf8ToOneUcs4Char(src, n); - if (v >= 0x10000) { - v -= 0x10000; - if (v > 0xFFFFF || dstlen < 2) { - *dstlenp = (origDstlen - dstlen); - if (cx) { - char buffer[10]; - JS_snprintf(buffer, 10, "0x%x", v + 0x10000); - JS_ReportErrorFlagsAndNumber(cx, - JSREPORT_ERROR, - js_GetErrorMessage, NULL, - JSMSG_UTF8_CHAR_TOO_LARGE, - buffer); - } - return JS_FALSE; - } - if (dstlen < 2) - goto bufferTooSmall; - if (dst) { - *dst++ = (jschar)((v >> 10) + 0xD800); - v = (jschar)((v & 0x3FF) + 0xDC00); - } - dstlen--; - } - } - if (!dstlen) - goto bufferTooSmall; - if (dst) - *dst++ = (jschar) v; - dstlen--; - offset += n; - src += n; - srclen -= n; - } - *dstlenp = (origDstlen - dstlen); - return JS_TRUE; - -badCharacter: - *dstlenp = (origDstlen - dstlen); - if (cx) { - char buffer[10]; - JS_snprintf(buffer, 10, "%d", offset); - JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, - js_GetErrorMessage, NULL, - JSMSG_MALFORMED_UTF8_CHAR, - buffer); - } - return JS_FALSE; - -bufferTooSmall: - *dstlenp = (origDstlen - dstlen); - if (cx) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BUFFER_TOO_SMALL); - } - return JS_FALSE; -} - -#else /* !JS_C_STRINGS_ARE_UTF8 */ - -JSBool -js_InflateStringToBuffer(JSContext* cx, const char *bytes, size_t length, - jschar *chars, size_t* charsLength) -{ - size_t i; - - if (length > *charsLength) { - for (i = 0; i < *charsLength; i++) - chars[i] = (unsigned char) bytes[i]; - if (cx) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BUFFER_TOO_SMALL); - } - return JS_FALSE; - } - for (i = 0; i < length; i++) - chars[i] = (unsigned char) bytes[i]; - *charsLength = length; - return JS_TRUE; -} - -jschar * -js_InflateString(JSContext *cx, const char *bytes, size_t *bytesLength) -{ - jschar *chars; - size_t i, length = *bytesLength; - - chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); - if (!chars) { - *bytesLength = 0; - return NULL; - } - for (i = 0; i < length; i++) - chars[i] = (unsigned char) bytes[i]; - chars[length] = 0; - *bytesLength = length; - return chars; -} - -JSBool -js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, size_t length, - char *bytes, size_t* bytesLength) -{ - size_t i; - - if (length > *bytesLength) { - for (i = 0; i < *bytesLength; i++) - bytes[i] = (char) chars[i]; - if (cx) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BUFFER_TOO_SMALL); - } - return JS_FALSE; - } - for (i = 0; i < length; i++) - bytes[i] = (char) chars[i]; - *bytesLength = length; - return JS_TRUE; -} - -/* - * 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[length] = 0; - return bytes; -} - -#endif /* !JS_C_STRINGS_ARE_UTF8 */ - -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 - * 1 bit XML 1.0 name start character - * 1 bit XML 1.0 name character - * 2 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 */ -0x00036089, /* 9 Nd, identifier part, decimal 16 */ -0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */ -0x0000001B, /* 11 Sk */ -0x00050017, /* 12 Pc, underscore */ -0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */ -0x0000000C, /* 14 Zs */ -0x0000001C, /* 15 So */ -0x00070182, /* 16 Ll, identifier start */ -0x0000600B, /* 17 No, decimal 16 */ -0x0000500B, /* 18 No, decimal 8 */ -0x0000800B, /* 19 No, strange */ -0x08270181, /* 20 Lu, hasLower (add 32), identifier start */ -0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */ -0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */ -0x00670181, /* 23 Lu, hasLower (add 1), identifier start */ -0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */ -0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */ -0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */ -0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */ -0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */ -0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */ -0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */ -0x33670181, /* 31 Lu, hasLower (add 205), identifier start */ -0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */ -0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */ -0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */ -0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */ -0x34670181, /* 36 Lu, hasLower (add 209), identifier start */ -0x35670181, /* 37 Lu, hasLower (add 213), identifier start */ -0x00070181, /* 38 Lu, identifier start */ -0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */ -0x00070185, /* 40 Lo, identifier start */ -0x36670181, /* 41 Lu, hasLower (add 217), identifier start */ -0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */ -0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */ -0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */ -0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */ -0x00000000, /* 46 unassigned */ -0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */ -0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */ -0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */ -0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */ -0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */ -0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */ -0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */ -0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */ -0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */ -0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */ -0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */ -0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */ -0x00070084, /* 59 Lm, identifier start */ -0x00030086, /* 60 Mn, identifier part */ -0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */ -0x09670181, /* 62 Lu, hasLower (add 37), identifier start */ -0x10270181, /* 63 Lu, hasLower (add 64), identifier start */ -0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */ -0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */ -0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */ -0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */ -0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */ -0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */ -0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */ -0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */ -0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */ -0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */ -0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */ -0x14270181, /* 75 Lu, hasLower (add 80), identifier start */ -0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */ -0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */ -0x00034089, /* 78 Nd, identifier part, decimal 0 */ -0x00000087, /* 79 Me */ -0x00030088, /* 80 Mc, identifier part */ -0x00037489, /* 81 Nd, identifier part, decimal 26 */ -0x00005A0B, /* 82 No, decimal 13 */ -0x00006E0B, /* 83 No, decimal 23 */ -0x0000740B, /* 84 No, decimal 26 */ -0x0000000B, /* 85 No */ -0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */ -0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */ -0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */ -0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */ -0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */ -0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */ -0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */ -0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */ -0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */ -0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */ -0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */ -0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */ -0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */ -0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */ -0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */ -0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */ -0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */ -0xE0A70181, /* 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 */ -0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */ -0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */ -0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */ -0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */ -0x0007818A, /* 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 */ -0x0007738A, /* 120 Nl, identifier start, decimal 25 */ -0x0007418A, /* 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; - - length = JSSTRING_LENGTH(str); - if (length == 0) { - *rval = STRING_TO_JSVAL(cx->runtime->emptyString); - return JS_TRUE; - } - - R = js_NewString(cx, NULL, 0, 0); - if (!R) - return JS_FALSE; - - hexBuf[0] = '%'; - hexBuf[3] = 0; - chars = JSSTRING_CHARS(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 = js_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; - - length = JSSTRING_LENGTH(str); - if (length == 0) { - *rval = STRING_TO_JSVAL(cx->runtime->emptyString); - return JS_TRUE; - } - - R = js_NewString(cx, NULL, 0, 0); - if (!R) - return JS_FALSE; - - chars = JSSTRING_CHARS(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; - argv[0] = STRING_TO_JSVAL(str); - 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; - argv[0] = STRING_TO_JSVAL(str); - 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; - argv[0] = STRING_TO_JSVAL(str); - 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; - argv[0] = STRING_TO_JSVAL(str); - 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. - */ -int -js_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 deleted file mode 100644 index 658a87f90..000000000 --- a/src/dom/js/jsstr.h +++ /dev/null @@ -1,482 +0,0 @@ -/* -*- 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 -#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_ISLETTER(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_ISIDPART(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) - -/* - * Per ECMA-262 15.10.2.6, these characters are the only ones that make up a - * "word", as far as a RegExp is concerned. If we want a Unicode-friendlier - * definition of "word", we should rename this macro to something regexp-y. - */ -#define JS_ISWORD(c) ((c) < 128 && (isalnum(c) || (c) == '_')) - -#define JS_ISIDSTART(c) (JS_ISLETTER(c) || (c) == '_' || (c) == '$') -#define JS_ISIDENT(c) (JS_ISIDPART(c) || (c) == '_' || (c) == '$') - -#define JS_ISXMLSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || \ - (c) == '\n') -#define JS_ISXMLNSSTART(c) ((JS_CCODE(c) & 0x00000100) || (c) == '_') -#define JS_ISXMLNS(c) ((JS_CCODE(c) & 0x00000080) || (c) == '.' || \ - (c) == '-' || (c) == '_') -#define JS_ISXMLNAMESTART(c) (JS_ISXMLNSSTART(c) || (c) == ':') -#define JS_ISXMLNAME(c) (JS_ISXMLNS(c) || (c) == ':') - -#define JS_ISDIGIT(c) (JS_CTYPE(c) == JSCT_DECIMAL_DIGIT_NUMBER) - -/* XXXbe unify on A/X/Y tbls, avoid ctype.h? */ -/* 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) ((jschar) ((JS_CCODE(c) & 0x00100000) \ - ? (c) - ((int32)JS_CCODE(c) >> 22) \ - : (c))) -#define JS_TOLOWER(c) ((jschar) ((JS_CCODE(c) & 0x00200000) \ - ? (c) + ((int32)JS_CCODE(c) >> 22) \ - : (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 JSClass js_StringClass; - -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 printable C string. - */ -extern JS_FRIEND_API(const char *) -js_ValueToPrintableString(JSContext *cx, jsval v); - -/* - * 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. length is updated with the length of the new string in jschars. - */ -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' jschars. - * The buffer is NOT null-terminated. - * cx may be NULL, which means no errors are thrown. - * The destination length needs to be initialized with the buffer size, takes the number of chars moved. - */ -extern JSBool -js_InflateStringToBuffer(JSContext* cx, const char *bytes, size_t length, jschar *chars, size_t* charsLength); - -/* - * Deflate JS chars to bytes into a buffer. - * 'bytes' must be large enough for 'length chars. - * The buffer is NOT null-terminated. - * cx may be NULL, which means no errors are thrown. - * The destination length needs to be initialized with the buffer size, takes the number of bytes moved. - */ -extern JSBool -js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, size_t charsLength, 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); - -/* - * 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. - */ -extern int -js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char); - -JS_END_EXTERN_C - -#endif /* jsstr_h___ */ diff --git a/src/dom/js/jstypes.h b/src/dom/js/jstypes.h deleted file mode 100644 index 1c24293b5..000000000 --- a/src/dom/js/jstypes.h +++ /dev/null @@ -1,421 +0,0 @@ -/* -*- 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 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 - -/*********************************************************************** -** 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 */ - -#else /* Unix */ - -#ifdef HAVE_VISIBILITY_PRAGMA -#define JS_EXTERNAL_VIS __attribute__((visibility ("default"))) -#else -#define JS_EXTERNAL_VIS -#endif - -#define JS_EXTERN_API(__type) extern JS_EXTERNAL_VIS __type -#define JS_EXPORT_API(__type) JS_EXTERNAL_VIS __type -#define JS_EXTERN_DATA(__type) extern JS_EXTERNAL_VIS __type -#define JS_EXPORT_DATA(__type) JS_EXTERNAL_VIS __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) JS_EXPORT_DATA (__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_PTR_TO_INT32 -** JS_PTR_TO_UINT32 -** JS_INT32_TO_PTR -** JS_UINT32_TO_PTR -** DESCRIPTION: -** Integer to pointer and pointer to integer conversion macros. -***********************************************************************/ -#define JS_PTR_TO_INT32(x) ((jsint)((char *)(x) - (char *)0)) -#define JS_PTR_TO_UINT32(x) ((jsuint)((char *)(x) - (char *)0)) -#define JS_INT32_TO_PTR(x) ((void *)((char *)0 + (jsint)(x))) -#define JS_UINT32_TO_PTR(x) ((void *)((char *)0 + (jsuint)(x))) - -/*********************************************************************** -** 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_WIN) && !defined(CROSS_COMPILE)) || defined (WINCE) -# 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_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" - -/*********************************************************************** -** MACROS: JS_LIKELY -** JS_UNLIKELY -** DESCRIPTION: -** These macros allow you to give a hint to the compiler about branch -** probability so that it can better optimize. Use them like this: -** -** if (JS_LIKELY(v == 1)) { -** ... expected code path ... -** } -** -** if (JS_UNLIKELY(v == 0)) { -** ... non-expected code path ... -** } -** -***********************************************************************/ -#if defined(__GNUC__) && (__GNUC__ > 2) -#define JS_LIKELY(x) (__builtin_expect((x), 1)) -#define JS_UNLIKELY(x) (__builtin_expect((x), 0)) -#else -#define JS_LIKELY(x) (x) -#define JS_UNLIKELY(x) (x) -#endif - -JS_END_EXTERN_C - -#endif /* jstypes_h___ */ diff --git a/src/dom/js/jsutil.c b/src/dom/js/jsutil.c deleted file mode 100644 index d7fab0f88..000000000 --- a/src/dom/js/jsutil.c +++ /dev/null @@ -1,192 +0,0 @@ -/* -*- 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 ***** */ - -/* - * PR assertion checker. - */ -#include "jsstddef.h" -#include -#include -#include "jstypes.h" -#include "jsutil.h" - -#ifdef WIN32 -# include -#endif - -JS_PUBLIC_API(void) JS_Assert(const char *s, const char *file, JSIntn ln) -{ - fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); -#if defined(WIN32) - DebugBreak(); - exit(3); -#endif -#if defined(XP_OS2) - asm("int $3"); -#endif - abort(); -} - -#if defined DEBUG_notme && defined XP_UNIX - -#define __USE_GNU 1 -#include -#include -#include -#include "jshash.h" -#include "jsprf.h" - -JSCallsite js_calltree_root = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL}; - -static JSCallsite * -CallTree(uint32 *bp) -{ - uint32 *bpup, *bpdown, pc; - JSCallsite *parent, *site, **csp; - Dl_info info; - int ok, offset; - const char *symbol; - char *method; - - /* Reverse the stack frame list to avoid recursion. */ - bpup = NULL; - for (;;) { - bpdown = (uint32*) bp[0]; - bp[0] = (uint32) bpup; - if ((uint32*) bpdown[0] < bpdown) - break; - bpup = bp; - bp = bpdown; - } - - /* Reverse the stack again, finding and building a path in the tree. */ - parent = &js_calltree_root; - do { - bpup = (uint32*) bp[0]; - bp[0] = (uint32) bpdown; - pc = bp[1]; - - csp = &parent->kids; - while ((site = *csp) != NULL) { - if (site->pc == pc) { - /* Put the most recently used site at the front of siblings. */ - *csp = site->siblings; - site->siblings = parent->kids; - parent->kids = site; - - /* Site already built -- go up the stack. */ - goto upward; - } - csp = &site->siblings; - } - - /* Check for recursion: see if pc is on our ancestor line. */ - for (site = parent; site; site = site->parent) { - if (site->pc == pc) - goto upward; - } - - /* - * Not in tree at all: let's find our symbolic callsite info. - * XXX static syms are masked by nearest lower global - */ - info.dli_fname = info.dli_sname = NULL; - ok = dladdr((void*) pc, &info); - if (ok < 0) { - fprintf(stderr, "dladdr failed!\n"); - return NULL; - } - -/* XXXbe sub 0x08040000? or something, see dbaron bug with tenthumbs comment */ - symbol = info.dli_sname; - offset = (char*)pc - (char*)info.dli_fbase; - method = symbol - ? strdup(symbol) - : JS_smprintf("%s+%X", - info.dli_fname ? info.dli_fname : "main", - offset); - if (!method) - return NULL; - - /* Create a new callsite record. */ - site = (JSCallsite *) malloc(sizeof(JSCallsite)); - if (!site) - return NULL; - - /* Insert the new site into the tree. */ - site->pc = pc; - site->name = method; - site->library = info.dli_fname; - site->offset = offset; - site->parent = parent; - site->siblings = parent->kids; - parent->kids = site; - site->kids = NULL; - - upward: - parent = site; - bpdown = bp; - bp = bpup; - } while (bp); - - return site; -} - -JSCallsite * -JS_Backtrace(int skip) -{ - jmp_buf jb; - uint32 *bp, *bpdown; - - setjmp(jb); - - /* Stack walking code adapted from Kipp's "leaky". */ - bp = (uint32*) jb[0].__jmpbuf[JB_BP]; - while (--skip >= 0) { - bpdown = (uint32*) *bp++; - if (bpdown < bp) - break; - bp = bpdown; - } - - return CallTree(bp); -} - -#endif /* DEBUG_notme && XP_UNIX */ diff --git a/src/dom/js/jsutil.h b/src/dom/js/jsutil.h deleted file mode 100644 index 5e26c16ae..000000000 --- a/src/dom/js/jsutil.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- 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 - -#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); - -#ifdef XP_UNIX - -typedef struct JSCallsite JSCallsite; - -struct JSCallsite { - uint32 pc; - char *name; - const char *library; - int offset; - JSCallsite *parent; - JSCallsite *siblings; - JSCallsite *kids; - void *handy; -}; - -extern JSCallsite *JS_Backtrace(int skip); - -#endif - -JS_END_EXTERN_C - -#endif /* jsutil_h___ */ diff --git a/src/dom/js/jsxdrapi.c b/src/dom/js/jsxdrapi.c deleted file mode 100644 index 0c9aeceed..000000000 --- a/src/dom/js/jsxdrapi.c +++ /dev/null @@ -1,686 +0,0 @@ -/* -*- 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 -#include "jstypes.h" -#include "jsutil.h" /* Added by JSIFY */ -#include "jsdhash.h" -#include "jsprf.h" -#include "jsapi.h" -#include "jscntxt.h" -#include "jsnum.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) -{ - jsdpun u; - - if (xdr->mode == JSXDR_ENCODE) - u.d = **dp; - if (!JS_XDRUint32(xdr, &u.s.lo) || !JS_XDRUint32(xdr, &u.s.hi)) - return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) { - *dp = JS_NewDouble(xdr->cx, u.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 deleted file mode 100644 index 874a62eeb..000000000 --- a/src/dom/js/jsxdrapi.h +++ /dev/null @@ -1,193 +0,0 @@ -/* -*- 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/jsxml.c b/src/dom/js/jsxml.c deleted file mode 100644 index e7cde2edf..000000000 --- a/src/dom/js/jsxml.c +++ /dev/null @@ -1,8295 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=4 sw=4 et tw=78: - * - * ***** 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 SpiderMonkey E4X code, released August, 2004. - * - * 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_XML_SUPPORT - -#include -#include -#include -#include "jstypes.h" -#include "jsbit.h" -#include "jsprf.h" -#include "jsutil.h" -#include "jsapi.h" -#include "jsarray.h" -#include "jsatom.h" -#include "jsbool.h" -#include "jscntxt.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 "jsxml.h" - -#ifdef DEBUG -#include /* for #ifdef DEBUG memset calls */ -#endif - -/* - * NOTES - * - in the js shell, you must use the -x command line option, or call - * options('xml') before compiling anything that uses XML literals - * - * TODO - * - XXXbe patrol - * - Fuse objects and their JSXML* private data into single GC-things - * - fix function::foo vs. x.(foo == 42) collision using proper namespacing - * - fix the !TCF_HAS_DEFXMLNS optimization in js_FoldConstants - * - JSCLASS_DOCUMENT_OBSERVER support -- live two-way binding to Gecko's DOM! - * - JS_TypeOfValue sure could use a cleaner interface to "types" - */ - -#ifdef DEBUG_brendan -#define METERING 1 -#endif - -#ifdef METERING -static struct { - jsrefcount qname; - jsrefcount qnameobj; - jsrefcount liveqname; - jsrefcount liveqnameobj; - jsrefcount namespace; - jsrefcount namespaceobj; - jsrefcount livenamespace; - jsrefcount livenamespaceobj; - jsrefcount xml; - jsrefcount xmlobj; - jsrefcount livexml; - jsrefcount livexmlobj; -} xml_stats; - -#define METER(x) JS_ATOMIC_INCREMENT(&(x)) -#define UNMETER(x) JS_ATOMIC_DECREMENT(&(x)) -#else -#define METER(x) /* nothing */ -#define UNMETER(x) /* nothing */ -#endif - -/* - * Random utilities and global functions. - */ -const char js_AnyName_str[] = "AnyName"; -const char js_AttributeName_str[] = "AttributeName"; -const char js_isXMLName_str[] = "isXMLName"; -const char js_XMLList_str[] = "XMLList"; -const char js_localName_str[] = "localName"; -const char js_xml_parent_str[] = "parent"; -const char js_prefix_str[] = "prefix"; -const char js_toXMLString_str[] = "toXMLString"; -const char js_uri_str[] = "uri"; - -const char js_amp_entity_str[] = "&"; -const char js_gt_entity_str[] = ">"; -const char js_lt_entity_str[] = "<"; -const char js_quot_entity_str[] = """; - -#define IS_EMPTY(str) (JSSTRING_LENGTH(str) == 0) -#define IS_STAR(str) (JSSTRING_LENGTH(str) == 1 && *JSSTRING_CHARS(str) == '*') - -static JSBool -xml_isXMLName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - *rval = BOOLEAN_TO_JSVAL(js_IsXMLName(cx, argv[0])); - return JS_TRUE; -} - -/* - * Namespace class and library functions. - */ -enum namespace_tinyid { - NAMESPACE_PREFIX = -1, - NAMESPACE_URI = -2 -}; - -static JSBool -namespace_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSXMLNamespace *ns; - - if (!JSVAL_IS_INT(id)) - return JS_TRUE; - - ns = (JSXMLNamespace *) - JS_GetInstancePrivate(cx, obj, &js_NamespaceClass.base, NULL); - if (!ns) - return JS_TRUE; - - switch (JSVAL_TO_INT(id)) { - case NAMESPACE_PREFIX: - *vp = ns->prefix ? STRING_TO_JSVAL(ns->prefix) : JSVAL_VOID; - break; - case NAMESPACE_URI: - *vp = STRING_TO_JSVAL(ns->uri); - break; - } - return JS_TRUE; -} - -static void -namespace_finalize(JSContext *cx, JSObject *obj) -{ - JSXMLNamespace *ns; - JSRuntime *rt; - - ns = (JSXMLNamespace *) JS_GetPrivate(cx, obj); - if (!ns) - return; - JS_ASSERT(ns->object == obj); - ns->object = NULL; - UNMETER(xml_stats.livenamespaceobj); - - rt = cx->runtime; - if (rt->functionNamespaceObject == obj) - rt->functionNamespaceObject = NULL; -} - -static void -namespace_mark_vector(JSContext *cx, JSXMLNamespace **vec, uint32 len, - void *arg) -{ - uint32 i; - JSXMLNamespace *ns; - - for (i = 0; i < len; i++) { - ns = vec[i]; - { -#ifdef GC_MARK_DEBUG - char buf[100]; - - JS_snprintf(buf, sizeof buf, "%s=%s", - ns->prefix ? JS_GetStringBytes(ns->prefix) : "", - JS_GetStringBytes(ns->uri)); -#else - const char *buf = NULL; -#endif - JS_MarkGCThing(cx, ns, buf, arg); - } - } -} - -static uint32 -namespace_mark(JSContext *cx, JSObject *obj, void *arg) -{ - JSXMLNamespace *ns; - - ns = (JSXMLNamespace *) JS_GetPrivate(cx, obj); - JS_MarkGCThing(cx, ns, js_private_str, arg); - return 0; -} - -static JSBool -namespace_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) -{ - JSXMLNamespace *ns, *ns2; - JSObject *obj2; - - ns = (JSXMLNamespace *) JS_GetPrivate(cx, obj); - JS_ASSERT(JSVAL_IS_OBJECT(v)); - obj2 = JSVAL_TO_OBJECT(v); - if (!obj2 || OBJ_GET_CLASS(cx, obj2) != &js_NamespaceClass.base) { - *bp = JS_FALSE; - } else { - ns2 = (JSXMLNamespace *) JS_GetPrivate(cx, obj2); - *bp = !js_CompareStrings(ns->uri, ns2->uri); - } - return JS_TRUE; -} - -JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass = { - { "Namespace", - JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED, - JS_PropertyStub, JS_PropertyStub, namespace_getProperty, NULL, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, namespace_finalize, - NULL, NULL, NULL, NULL, - NULL, NULL, namespace_mark, NULL }, - namespace_equality, - NULL, NULL, - JSCLASS_NO_RESERVED_MEMBERS -}; - -#define NAMESPACE_ATTRS \ - (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED) - -static JSPropertySpec namespace_props[] = { - {js_prefix_str, NAMESPACE_PREFIX, NAMESPACE_ATTRS, 0, 0}, - {js_uri_str, NAMESPACE_URI, NAMESPACE_ATTRS, 0, 0}, - {0,0,0,0,0} -}; - -static JSBool -namespace_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXMLNamespace *ns; - - ns = (JSXMLNamespace *) - JS_GetInstancePrivate(cx, obj, &js_NamespaceClass.base, argv); - if (!ns) - return JS_FALSE; - - *rval = STRING_TO_JSVAL(ns->uri); - return JS_TRUE; -} - -static JSFunctionSpec namespace_methods[] = { - {js_toString_str, namespace_toString, 0,0,0}, - {0,0,0,0,0} -}; - -JSXMLNamespace * -js_NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri, - JSBool declared) -{ - JSXMLNamespace *ns; - - ns = (JSXMLNamespace *) - js_NewGCThing(cx, GCX_NAMESPACE, sizeof(JSXMLNamespace)); - if (!ns) - return NULL; - ns->object = NULL; - ns->prefix = prefix; - ns->uri = uri; - ns->declared = declared; - METER(xml_stats.namespace); - METER(xml_stats.livenamespace); - return ns; -} - -void -js_MarkXMLNamespace(JSContext *cx, JSXMLNamespace *ns, void *arg) -{ - JS_MarkGCThing(cx, ns->object, js_object_str, arg); - JS_MarkGCThing(cx, ns->prefix, js_prefix_str, arg); - JS_MarkGCThing(cx, ns->uri, js_uri_str, arg); -} - -void -js_FinalizeXMLNamespace(JSContext *cx, JSXMLNamespace *ns) -{ - UNMETER(xml_stats.livenamespace); -} - -JSObject * -js_NewXMLNamespaceObject(JSContext *cx, JSString *prefix, JSString *uri, - JSBool declared) -{ - JSXMLNamespace *ns; - - ns = js_NewXMLNamespace(cx, prefix, uri, declared); - if (!ns) - return NULL; - return js_GetXMLNamespaceObject(cx, ns); -} - -JSObject * -js_GetXMLNamespaceObject(JSContext *cx, JSXMLNamespace *ns) -{ - JSObject *obj; - - obj = ns->object; - if (obj) { - JS_ASSERT(JS_GetPrivate(cx, obj) == ns); - return obj; - } - obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL); - if (!obj || !JS_SetPrivate(cx, obj, ns)) { - cx->newborn[GCX_OBJECT] = NULL; - return NULL; - } - ns->object = obj; - METER(xml_stats.namespaceobj); - METER(xml_stats.livenamespaceobj); - return obj; -} - -/* - * QName class and library functions. - */ -enum qname_tinyid { - QNAME_URI = -1, - QNAME_LOCALNAME = -2 -}; - -static JSBool -qname_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSXMLQName *qn; - - if (!JSVAL_IS_INT(id)) - return JS_TRUE; - - qn = (JSXMLQName *) - JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, NULL); - if (!qn) - return JS_TRUE; - - switch (JSVAL_TO_INT(id)) { - case QNAME_URI: - *vp = qn->uri ? STRING_TO_JSVAL(qn->uri) : JSVAL_NULL; - break; - case QNAME_LOCALNAME: - *vp = STRING_TO_JSVAL(qn->localName); - break; - } - return JS_TRUE; -} - -static void -qname_finalize(JSContext *cx, JSObject *obj) -{ - JSXMLQName *qn; - - qn = (JSXMLQName *) JS_GetPrivate(cx, obj); - if (!qn) - return; - JS_ASSERT(qn->object == obj); - qn->object = NULL; - UNMETER(xml_stats.liveqnameobj); -} - -static void -anyname_finalize(JSContext* cx, JSObject* obj) -{ - JSRuntime *rt; - - /* Make sure the next call to js_GetAnyName doesn't try to use obj. */ - rt = cx->runtime; - if (rt->anynameObject == obj) - rt->anynameObject = NULL; - - qname_finalize(cx, obj); -} - -static uint32 -qname_mark(JSContext *cx, JSObject *obj, void *arg) -{ - JSXMLQName *qn; - - qn = (JSXMLQName *) JS_GetPrivate(cx, obj); - JS_MarkGCThing(cx, qn, js_private_str, arg); - return 0; -} - -static JSBool -qname_identity(JSXMLQName *qna, JSXMLQName *qnb) -{ - if (!qna->uri ^ !qnb->uri) - return JS_FALSE; - if (qna->uri && js_CompareStrings(qna->uri, qnb->uri)) - return JS_FALSE; - return !js_CompareStrings(qna->localName, qnb->localName); -} - -static JSBool -qname_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) -{ - JSXMLQName *qn, *qn2; - JSObject *obj2; - - qn = (JSXMLQName *) JS_GetPrivate(cx, obj); - JS_ASSERT(JSVAL_IS_OBJECT(v)); - obj2 = JSVAL_TO_OBJECT(v); - if (!obj2 || OBJ_GET_CLASS(cx, obj2) != &js_QNameClass.base) { - *bp = JS_FALSE; - } else { - qn2 = (JSXMLQName *) JS_GetPrivate(cx, obj2); - *bp = qname_identity(qn, qn2); - } - return JS_TRUE; -} - -JS_FRIEND_DATA(JSExtendedClass) js_QNameClass = { - { "QName", - JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED, - JS_PropertyStub, JS_PropertyStub, qname_getProperty, NULL, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize, - NULL, NULL, NULL, NULL, - NULL, NULL, qname_mark, NULL }, - qname_equality, - NULL, NULL, - JSCLASS_NO_RESERVED_MEMBERS -}; - -/* - * Classes for the ECMA-357-internal types AttributeName and AnyName, which - * are like QName, except that they have no property getters. They share the - * qname_toString method, and therefore are exposed as constructable objects - * in this implementation. - */ -JS_FRIEND_DATA(JSClass) js_AttributeNameClass = { - js_AttributeName_str, JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize, - NULL, NULL, NULL, NULL, - NULL, NULL, qname_mark, NULL -}; - -JS_FRIEND_DATA(JSClass) js_AnyNameClass = { - js_AnyName_str, JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, anyname_finalize, - NULL, NULL, NULL, NULL, - NULL, NULL, qname_mark, NULL -}; - -#define QNAME_ATTRS \ - (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED) - -static JSPropertySpec qname_props[] = { - {js_uri_str, QNAME_URI, QNAME_ATTRS, 0, 0}, - {js_localName_str, QNAME_LOCALNAME, QNAME_ATTRS, 0, 0}, - {0,0,0,0,0} -}; - -static JSBool -qname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSClass *clasp; - JSXMLQName *qn; - JSString *str, *qualstr; - size_t length; - jschar *chars; - - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp == &js_AttributeNameClass || clasp == &js_AnyNameClass) { - qn = (JSXMLQName *) JS_GetPrivate(cx, obj); - } else { - qn = (JSXMLQName *) - JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, argv); - if (!qn) - return JS_FALSE; - } - - if (!qn->uri) { - /* No uri means wildcard qualifier. */ - str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom); - } else if (IS_EMPTY(qn->uri)) { - /* Empty string for uri means localName is in no namespace. */ - str = cx->runtime->emptyString; - } else { - qualstr = ATOM_TO_STRING(cx->runtime->atomState.qualifierAtom); - str = js_ConcatStrings(cx, qn->uri, qualstr); - if (!str) - return JS_FALSE; - } - str = js_ConcatStrings(cx, str, qn->localName); - if (!str) - return JS_FALSE; - - if (str && clasp == &js_AttributeNameClass) { - length = JSSTRING_LENGTH(str); - chars = (jschar *) JS_malloc(cx, (length + 2) * sizeof(jschar)); - if (!chars) - return JS_FALSE; - *chars = '@'; - js_strncpy(chars + 1, JSSTRING_CHARS(str), length); - 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 JSFunctionSpec qname_methods[] = { - {js_toString_str, qname_toString, 0,0,0}, - {0,0,0,0,0} -}; - -JSXMLQName * -js_NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, - JSString *localName) -{ - JSXMLQName *qn; - - qn = (JSXMLQName *) js_NewGCThing(cx, GCX_QNAME, sizeof(JSXMLQName)); - if (!qn) - return NULL; - qn->object = NULL; - qn->uri = uri; - qn->prefix = prefix; - qn->localName = localName; - METER(xml_stats.qname); - METER(xml_stats.liveqname); - return qn; -} - -void -js_MarkXMLQName(JSContext *cx, JSXMLQName *qn, void *arg) -{ - JS_MarkGCThing(cx, qn->object, js_object_str, arg); - JS_MarkGCThing(cx, qn->uri, js_uri_str, arg); - JS_MarkGCThing(cx, qn->prefix, js_prefix_str, arg); - JS_MarkGCThing(cx, qn->localName, js_localName_str, arg); -} - -void -js_FinalizeXMLQName(JSContext *cx, JSXMLQName *qn) -{ - UNMETER(xml_stats.liveqname); -} - -JSObject * -js_NewXMLQNameObject(JSContext *cx, JSString *uri, JSString *prefix, - JSString *localName) -{ - JSXMLQName *qn; - - qn = js_NewXMLQName(cx, uri, prefix, localName); - if (!qn) - return NULL; - return js_GetXMLQNameObject(cx, qn); -} - -JSObject * -js_GetXMLQNameObject(JSContext *cx, JSXMLQName *qn) -{ - JSObject *obj; - - obj = qn->object; - if (obj) { - JS_ASSERT(JS_GetPrivate(cx, obj) == qn); - return obj; - } - obj = js_NewObject(cx, &js_QNameClass.base, NULL, NULL); - if (!obj || !JS_SetPrivate(cx, obj, qn)) { - cx->newborn[GCX_OBJECT] = NULL; - return NULL; - } - qn->object = obj; - METER(xml_stats.qnameobj); - METER(xml_stats.liveqnameobj); - return obj; -} - -JSObject * -js_GetAttributeNameObject(JSContext *cx, JSXMLQName *qn) -{ - JSObject *obj; - - obj = qn->object; - if (obj) { - if (OBJ_GET_CLASS(cx, obj) == &js_AttributeNameClass) - return obj; - qn = js_NewXMLQName(cx, qn->uri, qn->prefix, qn->localName); - if (!qn) - return NULL; - } - - obj = js_NewObject(cx, &js_AttributeNameClass, NULL, NULL); - if (!obj || !JS_SetPrivate(cx, obj, qn)) { - cx->newborn[GCX_OBJECT] = NULL; - return NULL; - } - - qn->object = obj; - METER(xml_stats.qnameobj); - METER(xml_stats.liveqnameobj); - return obj; -} - -JSObject * -js_ConstructXMLQNameObject(JSContext *cx, jsval nsval, jsval lnval) -{ - jsval argv[2]; - - /* - * ECMA-357 11.1.2, - * The _QualifiedIdentifier : PropertySelector :: PropertySelector_ - * production, step 2. - */ - if (!JSVAL_IS_PRIMITIVE(nsval) && - OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(nsval)) == &js_AnyNameClass) { - nsval = JSVAL_NULL; - } - - argv[0] = nsval; - argv[1] = lnval; - return js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, argv); -} - -static JSBool -IsXMLName(const jschar *cp, size_t n) -{ - JSBool rv; - jschar c; - - rv = JS_FALSE; - if (n != 0 && JS_ISXMLNSSTART(*cp)) { - while (--n != 0) { - c = *++cp; - if (!JS_ISXMLNS(c)) - return rv; - } - rv = JS_TRUE; - } - return rv; -} - -JSBool -js_IsXMLName(JSContext *cx, jsval v) -{ - JSClass *clasp; - JSXMLQName *qn; - JSString *name; - JSErrorReporter older; - - /* - * Inline specialization of the QName constructor called with v passed as - * the only argument, to compute the localName for the constructed qname, - * without actually allocating the object or computing its uri and prefix. - * See ECMA-357 13.1.2.1 step 1 and 13.3.2. - */ - if (!JSVAL_IS_PRIMITIVE(v) && - (clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)), - clasp == &js_QNameClass.base || - clasp == &js_AttributeNameClass || - clasp == &js_AnyNameClass)) { - qn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); - name = qn->localName; - } else { - older = JS_SetErrorReporter(cx, NULL); - name = js_ValueToString(cx, v); - JS_SetErrorReporter(cx, older); - if (!name) { - JS_ClearPendingException(cx); - return JS_FALSE; - } - } - - return IsXMLName(JSSTRING_CHARS(name), JSSTRING_LENGTH(name)); -} - -static JSBool -Namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval urival, prefixval; - JSObject *uriobj; - JSBool isNamespace, isQName; - JSClass *clasp; - JSString *empty, *prefix; - JSXMLNamespace *ns, *ns2; - JSXMLQName *qn; - - urival = argv[argc > 1]; - isNamespace = isQName = JS_FALSE; - if (!JSVAL_IS_PRIMITIVE(urival)) { - uriobj = JSVAL_TO_OBJECT(urival); - clasp = OBJ_GET_CLASS(cx, uriobj); - isNamespace = (clasp == &js_NamespaceClass.base); - isQName = (clasp == &js_QNameClass.base); - } -#ifdef __GNUC__ /* suppress bogus gcc warnings */ - else uriobj = NULL; -#endif - - if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { - /* Namespace called as function. */ - if (argc == 1 && isNamespace) { - /* Namespace called with one Namespace argument is identity. */ - *rval = urival; - return JS_TRUE; - } - - /* Create and return a new QName object exactly as if constructed. */ - obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL); - if (!obj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - } - METER(xml_stats.namespaceobj); - METER(xml_stats.livenamespaceobj); - - /* - * Create and connect private data to rooted obj early, so we don't have - * to worry about rooting string newborns hanging off of the private data - * further below. - */ - empty = cx->runtime->emptyString; - ns = js_NewXMLNamespace(cx, empty, empty, JS_FALSE); - if (!ns) - return JS_FALSE; - if (!JS_SetPrivate(cx, obj, ns)) - return JS_FALSE; - ns->object = obj; - - if (argc == 1) { - if (isNamespace) { - ns2 = (JSXMLNamespace *) JS_GetPrivate(cx, uriobj); - ns->uri = ns2->uri; - ns->prefix = ns2->prefix; - } else if (isQName && - (qn = (JSXMLQName *) JS_GetPrivate(cx, uriobj))->uri) { - ns->uri = qn->uri; - ns->prefix = qn->prefix; - } else { - ns->uri = js_ValueToString(cx, urival); - if (!ns->uri) - return JS_FALSE; - - /* NULL here represents *undefined* in ECMA-357 13.2.2 3(c)iii. */ - if (!IS_EMPTY(ns->uri)) - ns->prefix = NULL; - } - } else if (argc == 2) { - if (isQName && - (qn = (JSXMLQName *) JS_GetPrivate(cx, uriobj))->uri) { - ns->uri = qn->uri; - } else { - ns->uri = js_ValueToString(cx, urival); - if (!ns->uri) - return JS_FALSE; - } - - prefixval = argv[0]; - if (IS_EMPTY(ns->uri)) { - if (!JSVAL_IS_VOID(prefixval)) { - prefix = js_ValueToString(cx, prefixval); - if (!prefix) - return JS_FALSE; - if (!IS_EMPTY(prefix)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XML_NAMESPACE, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(prefix))); - return JS_FALSE; - } - } - } else if (JSVAL_IS_VOID(prefixval) || !js_IsXMLName(cx, prefixval)) { - /* NULL here represents *undefined* in ECMA-357 13.2.2 4(d) etc. */ - ns->prefix = NULL; - } else { - prefix = js_ValueToString(cx, prefixval); - if (!prefix) - return JS_FALSE; - ns->prefix = prefix; - } - } - - return JS_TRUE; -} - -static JSBool -QName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval nameval, nsval; - JSBool isQName, isNamespace; - JSXMLQName *qn; - JSString *uri, *prefix, *name; - JSObject *nsobj; - JSClass *clasp; - JSXMLNamespace *ns; - - nameval = argv[argc > 1]; - isQName = - !JSVAL_IS_PRIMITIVE(nameval) && - OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(nameval)) == &js_QNameClass.base; - - if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { - /* QName called as function. */ - if (argc == 1 && isQName) { - /* QName called with one QName argument is identity. */ - *rval = nameval; - return JS_TRUE; - } - - /* - * Create and return a new QName object exactly as if constructed. - * Use the constructor's clasp so we can be shared by AttributeName - * (see below after this function). - */ - obj = js_NewObject(cx, - argv - ? JS_ValueToFunction(cx, argv[-2])->clasp - : &js_QNameClass.base, - NULL, NULL); - if (!obj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - } - METER(xml_stats.qnameobj); - METER(xml_stats.liveqnameobj); - - if (isQName) { - /* If namespace is not specified and name is a QName, clone it. */ - qn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(nameval)); - if (argc == 1) { - uri = qn->uri; - prefix = qn->prefix; - name = qn->localName; - goto out; - } - - /* Namespace and qname were passed -- use the qname's localName. */ - nameval = STRING_TO_JSVAL(qn->localName); - } - - if (argc == 0) { - name = cx->runtime->emptyString; - } else { - name = js_ValueToString(cx, nameval); - if (!name) - return JS_FALSE; - - /* Use argv[1] as a local root for name, even if it was not passed. */ - argv[1] = STRING_TO_JSVAL(name); - } - - nsval = argv[0]; - if (argc == 1 || JSVAL_IS_VOID(nsval)) { - if (IS_STAR(name)) { - nsval = JSVAL_NULL; - } else { - if (!js_GetDefaultXMLNamespace(cx, &nsval)) - return JS_FALSE; - } - } - - if (JSVAL_IS_NULL(nsval)) { - /* NULL prefix represents *undefined* in ECMA-357 13.3.2 5(a). */ - uri = prefix = NULL; - } else { - /* - * Inline specialization of the Namespace constructor called with - * nsval passed as the only argument, to compute the uri and prefix - * for the constructed namespace, without actually allocating the - * object or computing other members. See ECMA-357 13.3.2 6(a) and - * 13.2.2. - */ - isNamespace = isQName = JS_FALSE; - if (!JSVAL_IS_PRIMITIVE(nsval)) { - nsobj = JSVAL_TO_OBJECT(nsval); - clasp = OBJ_GET_CLASS(cx, nsobj); - isNamespace = (clasp == &js_NamespaceClass.base); - isQName = (clasp == &js_QNameClass.base); - } -#ifdef __GNUC__ /* suppress bogus gcc warnings */ - else nsobj = NULL; -#endif - - if (isNamespace) { - ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); - uri = ns->uri; - prefix = ns->prefix; - } else if (isQName && - (qn = (JSXMLQName *) JS_GetPrivate(cx, nsobj))->uri) { - uri = qn->uri; - prefix = qn->prefix; - } else { - uri = js_ValueToString(cx, nsval); - if (!uri) - return JS_FALSE; - argv[0] = STRING_TO_JSVAL(uri); /* local root */ - - /* NULL here represents *undefined* in ECMA-357 13.2.2 3(c)iii. */ - prefix = IS_EMPTY(uri) ? cx->runtime->emptyString : NULL; - } - } - -out: - qn = js_NewXMLQName(cx, uri, prefix, name); - if (!qn) - return JS_FALSE; - if (!JS_SetPrivate(cx, obj, qn)) - return JS_FALSE; - qn->object = obj; - return JS_TRUE; -} - -static JSBool -AttributeName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - /* - * Since js_AttributeNameClass was initialized, obj will have that as its - * class, not js_QNameClass. - */ - return QName(cx, obj, argc, argv, rval); -} - -/* - * XMLArray library functions. - */ -static JSBool -namespace_identity(const void *a, const void *b) -{ - const JSXMLNamespace *nsa = (const JSXMLNamespace *) a; - const JSXMLNamespace *nsb = (const JSXMLNamespace *) b; - - if (nsa->prefix && nsb->prefix) { - if (js_CompareStrings(nsa->prefix, nsb->prefix)) - return JS_FALSE; - } else { - if (nsa->prefix || nsb->prefix) - return JS_FALSE; - } - return !js_CompareStrings(nsa->uri, nsb->uri); -} - -static JSBool -attr_identity(const void *a, const void *b) -{ - const JSXML *xmla = (const JSXML *) a; - const JSXML *xmlb = (const JSXML *) b; - - return qname_identity(xmla->name, xmlb->name); -} - -static void -XMLArrayCursorInit(JSXMLArrayCursor *cursor, JSXMLArray *array) -{ - JSXMLArrayCursor *next; - - cursor->array = array; - cursor->index = 0; - next = cursor->next = array->cursors; - if (next) - next->prevp = &cursor->next; - cursor->prevp = &array->cursors; - array->cursors = cursor; - cursor->root = NULL; -} - -static void -XMLArrayCursorFinish(JSXMLArrayCursor *cursor) -{ - JSXMLArrayCursor *next; - - if (!cursor->array) - return; - next = cursor->next; - if (next) - next->prevp = cursor->prevp; - *cursor->prevp = next; - cursor->array = NULL; -} - -static void * -XMLArrayCursorNext(JSXMLArrayCursor *cursor) -{ - JSXMLArray *array; - - array = cursor->array; - if (!array || cursor->index >= array->length) - return NULL; - return cursor->root = array->vector[cursor->index++]; -} - -static void * -XMLArrayCursorItem(JSXMLArrayCursor *cursor) -{ - JSXMLArray *array; - - array = cursor->array; - if (!array || cursor->index >= array->length) - return NULL; - return cursor->root = array->vector[cursor->index]; -} - -static void -XMLArrayCursorMark(JSContext *cx, JSXMLArrayCursor *cursor) -{ - while (cursor) { - GC_MARK(cx, cursor->root, "cursor->root", NULL); - cursor = cursor->next; - } -} - -/* NB: called with null cx from the GC, via xml_mark => XMLArrayTrim. */ -static JSBool -XMLArraySetCapacity(JSContext *cx, JSXMLArray *array, uint32 capacity) -{ - void **vector; - - if (capacity == 0) { - /* We could let realloc(p, 0) free this, but purify gets confused. */ - if (array->vector) - free(array->vector); - vector = NULL; - } else { - if ((size_t)capacity > ~(size_t)0 / sizeof(void *) || - !(vector = (void **) - realloc(array->vector, capacity * sizeof(void *)))) { - if (cx) - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - } - array->capacity = JSXML_PRESET_CAPACITY | capacity; - array->vector = vector; - return JS_TRUE; -} - -static void -XMLArrayTrim(JSXMLArray *array) -{ - if (array->capacity & JSXML_PRESET_CAPACITY) - return; - if (array->length < array->capacity) - XMLArraySetCapacity(NULL, array, array->length); -} - -static JSBool -XMLArrayInit(JSContext *cx, JSXMLArray *array, uint32 capacity) -{ - array->length = array->capacity = 0; - array->vector = NULL; - array->cursors = NULL; - return capacity == 0 || XMLArraySetCapacity(cx, array, capacity); -} - -static void -XMLArrayFinish(JSContext *cx, JSXMLArray *array) -{ - JSXMLArrayCursor *cursor; - - JS_free(cx, array->vector); - - while ((cursor = array->cursors) != NULL) - XMLArrayCursorFinish(cursor); - -#ifdef DEBUG - memset(array, 0xd5, sizeof *array); -#endif -} - -#define XML_NOT_FOUND ((uint32) -1) - -static uint32 -XMLArrayFindMember(const JSXMLArray *array, void *elt, JSIdentityOp identity) -{ - void **vector; - uint32 i, n; - - /* The identity op must not reallocate array->vector. */ - vector = array->vector; - if (identity) { - for (i = 0, n = array->length; i < n; i++) { - if (identity(vector[i], elt)) - return i; - } - } else { - for (i = 0, n = array->length; i < n; i++) { - if (vector[i] == elt) - return i; - } - } - return XML_NOT_FOUND; -} - -/* - * Grow array vector capacity by powers of two to LINEAR_THRESHOLD, and after - * that, grow by LINEAR_INCREMENT. Both must be powers of two, and threshold - * should be greater than increment. - */ -#define LINEAR_THRESHOLD 256 -#define LINEAR_INCREMENT 32 - -static JSBool -XMLArrayAddMember(JSContext *cx, JSXMLArray *array, uint32 index, void *elt) -{ - uint32 capacity, i; - int log2; - void **vector; - - if (index >= array->length) { - if (index >= JSXML_CAPACITY(array)) { - /* Arrange to clear JSXML_PRESET_CAPACITY from array->capacity. */ - capacity = index + 1; - if (index >= LINEAR_THRESHOLD) { - capacity = JS_ROUNDUP(capacity, LINEAR_INCREMENT); - } else { - JS_CEILING_LOG2(log2, capacity); - capacity = JS_BIT(log2); - } - if ((size_t)capacity > ~(size_t)0 / sizeof(void *) || - !(vector = (void **) - realloc(array->vector, capacity * sizeof(void *)))) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - array->capacity = capacity; - array->vector = vector; - for (i = array->length; i < index; i++) - vector[i] = NULL; - } - array->length = index + 1; - } - - array->vector[index] = elt; - return JS_TRUE; -} - -static JSBool -XMLArrayInsert(JSContext *cx, JSXMLArray *array, uint32 i, uint32 n) -{ - uint32 j; - JSXMLArrayCursor *cursor; - - j = array->length; - JS_ASSERT(i <= j); - if (!XMLArraySetCapacity(cx, array, j + n)) - return JS_FALSE; - - array->length = j + n; - JS_ASSERT(n != (uint32)-1); - while (j != i) { - --j; - array->vector[j + n] = array->vector[j]; - } - - for (cursor = array->cursors; cursor; cursor = cursor->next) { - if (cursor->index > i) - cursor->index += n; - } - return JS_TRUE; -} - -static void * -XMLArrayDelete(JSContext *cx, JSXMLArray *array, uint32 index, JSBool compress) -{ - uint32 length; - void **vector, *elt; - JSXMLArrayCursor *cursor; - - length = array->length; - if (index >= length) - return NULL; - - vector = array->vector; - elt = vector[index]; - if (compress) { - while (++index < length) - vector[index-1] = vector[index]; - array->length = length - 1; - array->capacity = JSXML_CAPACITY(array); - } else { - vector[index] = NULL; - } - - for (cursor = array->cursors; cursor; cursor = cursor->next) { - if (cursor->index > index) - --cursor->index; - } - return elt; -} - -static void -XMLArrayTruncate(JSContext *cx, JSXMLArray *array, uint32 length) -{ - void **vector; - - JS_ASSERT(!array->cursors); - if (length >= array->length) - return; - - if (length == 0) { - if (array->vector) - free(array->vector); - vector = NULL; - } else { - vector = realloc(array->vector, length * sizeof(void *)); - if (!vector) - return; - } - - if (array->length > length) - array->length = length; - array->capacity = length; - array->vector = vector; -} - -#define XMLARRAY_FIND_MEMBER(a,e,f) XMLArrayFindMember(a, (void *)(e), f) -#define XMLARRAY_HAS_MEMBER(a,e,f) (XMLArrayFindMember(a, (void *)(e), f) != \ - XML_NOT_FOUND) -#define XMLARRAY_MEMBER(a,i,t) (((i) < (a)->length) \ - ? (t *) (a)->vector[i] \ - : NULL) -#define XMLARRAY_SET_MEMBER(a,i,e) JS_BEGIN_MACRO \ - if ((a)->length <= (i)) \ - (a)->length = (i) + 1; \ - ((a)->vector[i] = (void *)(e)); \ - JS_END_MACRO -#define XMLARRAY_ADD_MEMBER(x,a,i,e)XMLArrayAddMember(x, a, i, (void *)(e)) -#define XMLARRAY_INSERT(x,a,i,n) XMLArrayInsert(x, a, i, n) -#define XMLARRAY_APPEND(x,a,e) XMLARRAY_ADD_MEMBER(x, a, (a)->length, (e)) -#define XMLARRAY_DELETE(x,a,i,c,t) ((t *) XMLArrayDelete(x, a, i, c)) -#define XMLARRAY_TRUNCATE(x,a,n) XMLArrayTruncate(x, a, n) - -/* - * Define XML setting property strings and constants early, so everyone can - * use the same names and their magic numbers (tinyids, flags). - */ -static const char js_ignoreComments_str[] = "ignoreComments"; -static const char js_ignoreProcessingInstructions_str[] - = "ignoreProcessingInstructions"; -static const char js_ignoreWhitespace_str[] = "ignoreWhitespace"; -static const char js_prettyPrinting_str[] = "prettyPrinting"; -static const char js_prettyIndent_str[] = "prettyIndent"; - -/* - * NB: These XML static property tinyids must - * (a) not collide with the generic negative tinyids at the top of jsfun.c; - * (b) index their corresponding xml_static_props array elements. - * Don't change 'em! - */ -enum xml_static_tinyid { - XML_IGNORE_COMMENTS, - XML_IGNORE_PROCESSING_INSTRUCTIONS, - XML_IGNORE_WHITESPACE, - XML_PRETTY_PRINTING, - XML_PRETTY_INDENT -}; - -static JSBool -xml_setting_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - return JS_TRUE; -} - -static JSBool -xml_setting_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSBool b; - uint8 flag; - - JS_ASSERT(JSVAL_IS_INT(id)); - if (!js_ValueToBoolean(cx, *vp, &b)) - return JS_FALSE; - - flag = JS_BIT(JSVAL_TO_INT(id)); - if (b) - cx->xmlSettingFlags |= flag; - else - cx->xmlSettingFlags &= ~flag; - return JS_TRUE; -} - -static JSPropertySpec xml_static_props[] = { - {js_ignoreComments_str, XML_IGNORE_COMMENTS, JSPROP_PERMANENT, - xml_setting_getter, xml_setting_setter}, - {js_ignoreProcessingInstructions_str, - XML_IGNORE_PROCESSING_INSTRUCTIONS, JSPROP_PERMANENT, - xml_setting_getter, xml_setting_setter}, - {js_ignoreWhitespace_str, XML_IGNORE_WHITESPACE, JSPROP_PERMANENT, - xml_setting_getter, xml_setting_setter}, - {js_prettyPrinting_str, XML_PRETTY_PRINTING, JSPROP_PERMANENT, - xml_setting_getter, xml_setting_setter}, - {js_prettyIndent_str, XML_PRETTY_INDENT, JSPROP_PERMANENT, - xml_setting_getter, NULL}, - {0,0,0,0,0} -}; - -/* Derive cx->xmlSettingFlags bits from xml_static_props tinyids. */ -#define XSF_IGNORE_COMMENTS JS_BIT(XML_IGNORE_COMMENTS) -#define XSF_IGNORE_PROCESSING_INSTRUCTIONS \ - JS_BIT(XML_IGNORE_PROCESSING_INSTRUCTIONS) -#define XSF_IGNORE_WHITESPACE JS_BIT(XML_IGNORE_WHITESPACE) -#define XSF_PRETTY_PRINTING JS_BIT(XML_PRETTY_PRINTING) -#define XSF_CACHE_VALID JS_BIT(XML_PRETTY_INDENT) - -/* - * Extra, unrelated but necessarily disjoint flag used by ParseNodeToXML. - * This flag means a couple of things: - * - * - The top JSXML created for a parse tree must have an object owning it. - * - * - That the default namespace normally inherited from the temporary - * tag that wraps a runtime-concatenated XML source - * string must, in the case of a precompiled XML object tree, inherit via - * ad-hoc code in ParseNodeToXML. - * - * Because of the second purpose, we name this flag XSF_PRECOMPILED_ROOT. - */ -#define XSF_PRECOMPILED_ROOT (XSF_CACHE_VALID << 1) - -/* Macros for special-casing xml:, xmlns= and xmlns:foo= in ParseNodeToQName. */ -#define IS_XML(str) \ - (JSSTRING_LENGTH(str) == 3 && IS_XML_CHARS(JSSTRING_CHARS(str))) - -#define IS_XMLNS(str) \ - (JSSTRING_LENGTH(str) == 5 && IS_XMLNS_CHARS(JSSTRING_CHARS(str))) - -#define IS_XML_CHARS(chars) \ - (JS_TOLOWER((chars)[0]) == 'x' && \ - JS_TOLOWER((chars)[1]) == 'm' && \ - JS_TOLOWER((chars)[2]) == 'l') - -#define HAS_NS_AFTER_XML(chars) \ - (JS_TOLOWER((chars)[3]) == 'n' && \ - JS_TOLOWER((chars)[4]) == 's') - -#define IS_XMLNS_CHARS(chars) \ - (IS_XML_CHARS(chars) && HAS_NS_AFTER_XML(chars)) - -#define STARTS_WITH_XML(chars,length) \ - (length >= 3 && IS_XML_CHARS(chars)) - -static const char xml_namespace_str[] = "http://www.w3.org/XML/1998/namespace"; -static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/"; - -static JSXMLQName * -ParseNodeToQName(JSContext *cx, JSParseNode *pn, JSXMLArray *inScopeNSes, - JSBool isAttributeName) -{ - JSString *str, *uri, *prefix, *localName; - size_t length, offset; - const jschar *start, *limit, *colon; - uint32 n; - JSXMLNamespace *ns; - - JS_ASSERT(pn->pn_arity == PN_NULLARY); - str = ATOM_TO_STRING(pn->pn_atom); - length = JSSTRING_LENGTH(str); - start = JSSTRING_CHARS(str); - JS_ASSERT(length != 0 && *start != '@'); - JS_ASSERT(length != 1 || *start != '*'); - - uri = cx->runtime->emptyString; - limit = start + length; - colon = js_strchr_limit(start, ':', limit); - if (colon) { - offset = PTRDIFF(colon, start, jschar); - prefix = js_NewDependentString(cx, str, 0, offset, 0); - if (!prefix) - return NULL; - - if (STARTS_WITH_XML(start, offset)) { - if (offset == 3) { - uri = JS_InternString(cx, xml_namespace_str); - if (!uri) - return NULL; - } else if (offset == 5 && HAS_NS_AFTER_XML(start)) { - uri = JS_InternString(cx, xmlns_namespace_str); - if (!uri) - return NULL; - } else { - uri = NULL; - } - } else { - uri = NULL; - n = inScopeNSes->length; - while (n != 0) { - --n; - ns = XMLARRAY_MEMBER(inScopeNSes, n, JSXMLNamespace); - if (ns->prefix && !js_CompareStrings(ns->prefix, prefix)) { - uri = ns->uri; - break; - } - } - } - - if (!uri) { - js_ReportCompileErrorNumber(cx, pn, - JSREPORT_PN | JSREPORT_ERROR, - JSMSG_BAD_XML_NAMESPACE, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(prefix))); - return NULL; - } - - localName = js_NewStringCopyN(cx, colon + 1, length - (offset + 1), 0); - if (!localName) - return NULL; - } else { - if (isAttributeName) { - /* - * An unprefixed attribute is not in any namespace, so set prefix - * as well as uri to the empty string. - */ - prefix = uri; - } else { - /* - * Loop from back to front looking for the closest declared default - * namespace. - */ - n = inScopeNSes->length; - while (n != 0) { - --n; - ns = XMLARRAY_MEMBER(inScopeNSes, n, JSXMLNamespace); - if (!ns->prefix || IS_EMPTY(ns->prefix)) { - uri = ns->uri; - break; - } - } - prefix = NULL; - } - localName = str; - } - - return js_NewXMLQName(cx, uri, prefix, localName); -} - -static JSString * -ChompXMLWhitespace(JSContext *cx, JSString *str) -{ - size_t length, newlength, offset; - const jschar *cp, *start, *end; - jschar c; - - length = JSSTRING_LENGTH(str); - for (cp = start = JSSTRING_CHARS(str), end = cp + length; cp < end; cp++) { - c = *cp; - if (!JS_ISXMLSPACE(c)) - break; - } - while (end > cp) { - c = end[-1]; - if (!JS_ISXMLSPACE(c)) - break; - --end; - } - newlength = PTRDIFF(end, cp, jschar); - if (newlength == length) - return str; - offset = PTRDIFF(cp, start, jschar); - return js_NewDependentString(cx, str, offset, newlength, 0); -} - -static JSXML * -ParseNodeToXML(JSContext *cx, JSParseNode *pn, JSXMLArray *inScopeNSes, - uintN flags) -{ - JSXML *xml, *kid, *attr, *attrj; - JSString *str; - uint32 length, n, i, j; - JSParseNode *pn2, *pn3, *head, **pnp; - JSXMLNamespace *ns; - JSXMLQName *qn, *attrjqn; - JSXMLClass xml_class; - -#define PN2X_SKIP_CHILD ((JSXML *) 1) - - /* - * Cases return early to avoid common code that gets an outermost xml's - * object, which protects GC-things owned by xml and its descendants from - * garbage collection. - */ - xml = NULL; - if (!JS_EnterLocalRootScope(cx)) - return NULL; - switch (pn->pn_type) { - case TOK_XMLELEM: - length = inScopeNSes->length; - pn2 = pn->pn_head; - xml = ParseNodeToXML(cx, pn2, inScopeNSes, flags); - if (!xml) - goto fail; - if (js_PushLocalRoot(cx, cx->localRootStack, (jsval)xml) < 0) - goto fail; - - flags &= ~XSF_PRECOMPILED_ROOT; - n = pn->pn_count; - JS_ASSERT(n >= 2); - n -= 2; - if (!XMLArraySetCapacity(cx, &xml->xml_kids, n)) - goto fail; - - i = 0; - while ((pn2 = pn2->pn_next) != NULL) { - if (!pn2->pn_next) { - /* Don't append the end tag! */ - JS_ASSERT(pn2->pn_type == TOK_XMLETAGO); - break; - } - - if ((flags & XSF_IGNORE_WHITESPACE) && - n > 1 && pn2->pn_type == TOK_XMLSPACE) { - --n; - continue; - } - - kid = ParseNodeToXML(cx, pn2, inScopeNSes, flags); - if (kid == PN2X_SKIP_CHILD) { - --n; - continue; - } - - if (!kid) - goto fail; - - /* Store kid in xml right away, to protect it from GC. */ - XMLARRAY_SET_MEMBER(&xml->xml_kids, i, kid); - kid->parent = xml; - ++i; - - /* XXX where is this documented in an XML spec, or in E4X? */ - if ((flags & XSF_IGNORE_WHITESPACE) && - n > 1 && kid->xml_class == JSXML_CLASS_TEXT) { - str = ChompXMLWhitespace(cx, kid->xml_value); - if (!str) - goto fail; - kid->xml_value = str; - } - } - - JS_ASSERT(i == n); - if (n < pn->pn_count - 2) - XMLArrayTrim(&xml->xml_kids); - XMLARRAY_TRUNCATE(cx, inScopeNSes, length); - break; - - case TOK_XMLLIST: - xml = js_NewXML(cx, JSXML_CLASS_LIST); - if (!xml) - goto fail; - - n = pn->pn_count; - if (!XMLArraySetCapacity(cx, &xml->xml_kids, n)) - goto fail; - - i = 0; - for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { - /* - * Always ignore insignificant whitespace in lists -- we shouldn't - * condition this on an XML.ignoreWhitespace setting when the list - * constructor is XMLList (note XML/XMLList unification hazard). - */ - if (pn2->pn_type == TOK_XMLSPACE) { - --n; - continue; - } - - kid = ParseNodeToXML(cx, pn2, inScopeNSes, flags); - if (kid == PN2X_SKIP_CHILD) { - --n; - continue; - } - - if (!kid) - goto fail; - - XMLARRAY_SET_MEMBER(&xml->xml_kids, i, kid); - ++i; - } - - if (n < pn->pn_count) - XMLArrayTrim(&xml->xml_kids); - break; - - case TOK_XMLSTAGO: - case TOK_XMLPTAGC: - length = inScopeNSes->length; - pn2 = pn->pn_head; - JS_ASSERT(pn2->pn_type == TOK_XMLNAME); - if (pn2->pn_arity == PN_LIST) - goto syntax; - - xml = js_NewXML(cx, JSXML_CLASS_ELEMENT); - if (!xml) - goto fail; - - /* First pass: check syntax and process namespace declarations. */ - JS_ASSERT(pn->pn_count >= 1); - n = pn->pn_count - 1; - pnp = &pn2->pn_next; - head = *pnp; - while ((pn2 = *pnp) != NULL) { - size_t length; - const jschar *chars; - - if (pn2->pn_type != TOK_XMLNAME || pn2->pn_arity != PN_NULLARY) - goto syntax; - - /* Enforce "Well-formedness constraint: Unique Att Spec". */ - for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { - if (pn3->pn_atom == pn2->pn_atom) { - js_ReportCompileErrorNumber(cx, pn2, - JSREPORT_PN | JSREPORT_ERROR, - JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); - goto fail; - } - } - - str = ATOM_TO_STRING(pn2->pn_atom); - pn2 = pn2->pn_next; - JS_ASSERT(pn2); - if (pn2->pn_type != TOK_XMLATTR) - goto syntax; - - length = JSSTRING_LENGTH(str); - chars = JSSTRING_CHARS(str); - if (length >= 5 && - IS_XMLNS_CHARS(chars) && - (length == 5 || chars[5] == ':')) { - JSString *uri, *prefix; - - uri = ATOM_TO_STRING(pn2->pn_atom); - if (length == 5) { - /* 10.3.2.1. Step 6(h)(i)(1)(a). */ - prefix = cx->runtime->emptyString; - } else { - prefix = js_NewStringCopyN(cx, chars + 6, length - 6, 0); - if (!prefix) - goto fail; - } - - /* - * Once the new ns is appended to xml->xml_namespaces, it is - * protected from GC by the object that owns xml -- which is - * either xml->object if outermost, or the object owning xml's - * oldest ancestor if !outermost. - */ - ns = js_NewXMLNamespace(cx, prefix, uri, JS_TRUE); - if (!ns) - goto fail; - - /* - * Don't add a namespace that's already in scope. If someone - * extracts a child property from its parent via [[Get]], then - * we enforce the invariant, noted many times in ECMA-357, that - * the child's namespaces form a possibly-improper superset of - * its ancestors' namespaces. - */ - if (!XMLARRAY_HAS_MEMBER(inScopeNSes, ns, namespace_identity)) { - if (!XMLARRAY_APPEND(cx, inScopeNSes, ns) || - !XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) { - goto fail; - } - } - - JS_ASSERT(n >= 2); - n -= 2; - *pnp = pn2->pn_next; - /* XXXbe recycle pn2 */ - continue; - } - - pnp = &pn2->pn_next; - } - - /* - * If called from js_ParseNodeToXMLObject, emulate the effect of the - * ... wrapping done by "ToXML Applied to - * the String Type" (ECMA-357 10.3.1). - */ - if (flags & XSF_PRECOMPILED_ROOT) { - JS_ASSERT(length >= 1); - ns = XMLARRAY_MEMBER(inScopeNSes, 0, JSXMLNamespace); - JS_ASSERT(!XMLARRAY_HAS_MEMBER(&xml->xml_namespaces, ns, - namespace_identity)); - ns = js_NewXMLNamespace(cx, ns->prefix, ns->uri, JS_FALSE); - if (!ns) - goto fail; - if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) - goto fail; - } - XMLArrayTrim(&xml->xml_namespaces); - - /* Second pass: process tag name and attributes, using namespaces. */ - pn2 = pn->pn_head; - qn = ParseNodeToQName(cx, pn2, inScopeNSes, JS_FALSE); - if (!qn) - goto fail; - xml->name = qn; - - JS_ASSERT((n & 1) == 0); - n >>= 1; - if (!XMLArraySetCapacity(cx, &xml->xml_attrs, n)) - goto fail; - - for (i = 0; (pn2 = pn2->pn_next) != NULL; i++) { - qn = ParseNodeToQName(cx, pn2, inScopeNSes, JS_TRUE); - if (!qn) { - xml->xml_attrs.length = i; - goto fail; - } - - /* - * Enforce "Well-formedness constraint: Unique Att Spec", part 2: - * this time checking local name and namespace URI. - */ - for (j = 0; j < i; j++) { - attrj = XMLARRAY_MEMBER(&xml->xml_attrs, j, JSXML); - attrjqn = attrj->name; - if (!js_CompareStrings(attrjqn->uri, qn->uri) && - !js_CompareStrings(attrjqn->localName, qn->localName)) { - js_ReportCompileErrorNumber(cx, pn2, - JSREPORT_PN | JSREPORT_ERROR, - JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); - goto fail; - } - } - - pn2 = pn2->pn_next; - JS_ASSERT(pn2); - JS_ASSERT(pn2->pn_type == TOK_XMLATTR); - - attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); - if (!attr) - goto fail; - - XMLARRAY_SET_MEMBER(&xml->xml_attrs, i, attr); - attr->parent = xml; - attr->name = qn; - attr->xml_value = ATOM_TO_STRING(pn2->pn_atom); - } - - /* Point tag closes its own namespace scope. */ - if (pn->pn_type == TOK_XMLPTAGC) - XMLARRAY_TRUNCATE(cx, inScopeNSes, length); - break; - - case TOK_XMLSPACE: - case TOK_XMLTEXT: - case TOK_XMLCDATA: - case TOK_XMLCOMMENT: - case TOK_XMLPI: - str = ATOM_TO_STRING(pn->pn_atom); - qn = NULL; - if (pn->pn_type == TOK_XMLCOMMENT) { - if (flags & XSF_IGNORE_COMMENTS) - goto skip_child; - xml_class = JSXML_CLASS_COMMENT; - } else if (pn->pn_type == TOK_XMLPI) { - if (IS_XML(str)) { - js_ReportCompileErrorNumber(cx, pn, - JSREPORT_PN | JSREPORT_ERROR, - JSMSG_RESERVED_ID, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(str))); - goto fail; - } - - if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS) - goto skip_child; - - qn = ParseNodeToQName(cx, pn, inScopeNSes, JS_FALSE); - if (!qn) - goto fail; - - str = pn->pn_atom2 - ? ATOM_TO_STRING(pn->pn_atom2) - : cx->runtime->emptyString; - xml_class = JSXML_CLASS_PROCESSING_INSTRUCTION; - } else { - /* CDATA section content, or element text. */ - xml_class = JSXML_CLASS_TEXT; - } - - xml = js_NewXML(cx, xml_class); - if (!xml) - goto fail; - xml->name = qn; - if (pn->pn_type == TOK_XMLSPACE) - xml->xml_flags |= XMLF_WHITESPACE_TEXT; - xml->xml_value = str; - break; - - default: - goto syntax; - } - - JS_LeaveLocalRootScope(cx); - if ((flags & XSF_PRECOMPILED_ROOT) && !js_GetXMLObject(cx, xml)) - return NULL; - return xml; - -skip_child: - js_LeaveLocalRootScope(cx); - return PN2X_SKIP_CHILD; - -#undef PN2X_SKIP_CHILD - -syntax: - js_ReportCompileErrorNumber(cx, pn, JSREPORT_PN | JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); -fail: - JS_LeaveLocalRootScope(cx); - return NULL; -} - -/* - * XML helper, object-ops, and library functions. We start with the helpers, - * in ECMA-357 order, but merging XML (9.1) and XMLList (9.2) helpers. - */ -static JSBool -GetXMLSetting(JSContext *cx, const char *name, jsval *vp) -{ - jsval v; - - if (!js_FindConstructor(cx, NULL, js_XML_str, &v)) - return JS_FALSE; - if (!JSVAL_IS_FUNCTION(cx, v)) { - *vp = JSVAL_VOID; - return JS_TRUE; - } - return JS_GetProperty(cx, JSVAL_TO_OBJECT(v), name, vp); -} - -static JSBool -FillSettingsCache(JSContext *cx) -{ - int i; - const char *name; - jsval v; - JSBool isSet; - - /* Note: XML_PRETTY_INDENT is not a boolean setting. */ - for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) { - name = xml_static_props[i].name; - if (!GetXMLSetting(cx, name, &v) || !js_ValueToBoolean(cx, v, &isSet)) - return JS_FALSE; - if (isSet) - cx->xmlSettingFlags |= JS_BIT(i); - else - cx->xmlSettingFlags &= ~JS_BIT(i); - } - - cx->xmlSettingFlags |= XSF_CACHE_VALID; - return JS_TRUE; -} - -static JSBool -GetBooleanXMLSetting(JSContext *cx, const char *name, JSBool *bp) -{ - int i; - - if (!(cx->xmlSettingFlags & XSF_CACHE_VALID) && !FillSettingsCache(cx)) - return JS_FALSE; - - for (i = 0; xml_static_props[i].name; i++) { - if (!strcmp(xml_static_props[i].name, name)) { - *bp = (cx->xmlSettingFlags & JS_BIT(i)) != 0; - return JS_TRUE; - } - } - *bp = JS_FALSE; - return JS_TRUE; -} - -static JSBool -GetUint32XMLSetting(JSContext *cx, const char *name, uint32 *uip) -{ - jsval v; - - return GetXMLSetting(cx, name, &v) && js_ValueToECMAUint32(cx, v, uip); -} - -static JSBool -GetXMLSettingFlags(JSContext *cx, uintN *flagsp) -{ - JSBool flag; - - /* Just get the first flag to validate the setting flags cache. */ - if (!GetBooleanXMLSetting(cx, js_ignoreComments_str, &flag)) - return JS_FALSE; - *flagsp = cx->xmlSettingFlags; - return JS_TRUE; -} - -static JSXML * -ParseXMLSource(JSContext *cx, JSString *src) -{ - jsval nsval; - JSXMLNamespace *ns; - size_t urilen, srclen, length, offset, dstlen; - jschar *chars; - const jschar *srcp, *endp; - void *mark; - JSTokenStream *ts; - uintN lineno; - JSStackFrame *fp; - JSOp op; - JSParseNode *pn; - JSXML *xml; - JSXMLArray nsarray; - uintN flags; - - static const char prefix[] = ""; - static const char suffix[] = ""; - -#define constrlen(constr) (sizeof(constr) - 1) - - if (!js_GetDefaultXMLNamespace(cx, &nsval)) - return NULL; - ns = (JSXMLNamespace *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(nsval)); - - urilen = JSSTRING_LENGTH(ns->uri); - srclen = JSSTRING_LENGTH(src); - length = constrlen(prefix) + urilen + constrlen(middle) + srclen + - constrlen(suffix); - - chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); - if (!chars) - return NULL; - - dstlen = length; - js_InflateStringToBuffer(cx, prefix, constrlen(prefix), chars, &dstlen); - offset = dstlen; - js_strncpy(chars + offset, JSSTRING_CHARS(ns->uri), urilen); - offset += urilen; - dstlen = length - offset + 1; - js_InflateStringToBuffer(cx, middle, constrlen(middle), chars + offset, &dstlen); - offset += dstlen; - srcp = JSSTRING_CHARS(src); - js_strncpy(chars + offset, srcp, srclen); - offset += srclen; - dstlen = length - offset + 1; - js_InflateStringToBuffer(cx, suffix, constrlen(suffix), chars + offset, &dstlen); - chars [offset + dstlen] = 0; - - mark = JS_ARENA_MARK(&cx->tempPool); - ts = js_NewBufferTokenStream(cx, chars, length); - if (!ts) - return NULL; - for (fp = cx->fp; fp && !fp->pc; fp = fp->down) - continue; - if (fp) { - op = (JSOp) *fp->pc; - if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) { - ts->filename = fp->script->filename; - lineno = js_PCToLineNumber(cx, fp->script, fp->pc); - for (endp = srcp + srclen; srcp < endp; srcp++) - if (*srcp == '\n') - --lineno; - ts->lineno = lineno; - } - } - - JS_KEEP_ATOMS(cx->runtime); - pn = js_ParseXMLTokenStream(cx, cx->fp->scopeChain, ts, JS_FALSE); - xml = NULL; - if (pn && XMLArrayInit(cx, &nsarray, 1)) { - if (GetXMLSettingFlags(cx, &flags)) - xml = ParseNodeToXML(cx, pn, &nsarray, flags); - - XMLArrayFinish(cx, &nsarray); - } - JS_UNKEEP_ATOMS(cx->runtime); - - JS_ARENA_RELEASE(&cx->tempPool, mark); - JS_free(cx, chars); - return xml; - -#undef constrlen -} - -/* - * Errata in 10.3.1, 10.4.1, and 13.4.4.24 (at least). - * - * 10.3.1 Step 6(a) fails to NOTE that implementations that do not enforce - * the constraint: - * - * for all x belonging to XML: - * x.[[InScopeNamespaces]] >= x.[[Parent]].[[InScopeNamespaces]] - * - * must union x.[[InScopeNamespaces]] into x[0].[[InScopeNamespaces]] here - * (in new sub-step 6(a), renumbering the others to (b) and (c)). - * - * Same goes for 10.4.1 Step 7(a). - * - * In order for XML.prototype.namespaceDeclarations() to work correctly, the - * default namespace thereby unioned into x[0].[[InScopeNamespaces]] must be - * flagged as not declared, so that 13.4.4.24 Step 8(a) can exclude all such - * undeclared namespaces associated with x not belonging to ancestorNS. - */ -static JSXML * -OrphanXMLChild(JSContext *cx, JSXML *xml, uint32 i) -{ - JSXMLNamespace *ns; - - ns = XMLARRAY_MEMBER(&xml->xml_namespaces, 0, JSXMLNamespace); - xml = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (!ns || !xml) - return xml; - if (xml->xml_class == JSXML_CLASS_ELEMENT) { - if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) - return NULL; - ns->declared = JS_FALSE; - } - xml->parent = NULL; - return xml; -} - -static JSObject * -ToXML(JSContext *cx, jsval v) -{ - JSObject *obj; - JSXML *xml; - JSClass *clasp; - JSString *str; - uint32 length; - - if (JSVAL_IS_PRIMITIVE(v)) { - if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) - goto bad; - } else { - obj = JSVAL_TO_OBJECT(v); - if (OBJECT_IS_XML(cx, obj)) { - xml = (JSXML *) JS_GetPrivate(cx, obj); - if (xml->xml_class == JSXML_CLASS_LIST) { - if (xml->xml_kids.length != 1) - goto bad; - xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (xml) { - JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); - return js_GetXMLObject(cx, xml); - } - } - return obj; - } - - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) { - JS_ASSERT(0); - } - - if (clasp != &js_StringClass && - clasp != &js_NumberClass && - clasp != &js_BooleanClass) { - goto bad; - } - } - - str = js_ValueToString(cx, v); - if (!str) - return NULL; - if (IS_EMPTY(str)) { - length = 0; -#ifdef __GNUC__ /* suppress bogus gcc warnings */ - xml = NULL; -#endif - } else { - xml = ParseXMLSource(cx, str); - if (!xml) - return NULL; - length = JSXML_LENGTH(xml); - } - - if (length == 0) { - obj = js_NewXMLObject(cx, JSXML_CLASS_TEXT); - if (!obj) - return NULL; - } else if (length == 1) { - xml = OrphanXMLChild(cx, xml, 0); - if (!xml) - return NULL; - obj = js_GetXMLObject(cx, xml); - if (!obj) - return NULL; - } else { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SYNTAX_ERROR); - return NULL; - } - return obj; - -bad: - str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, v, NULL); - if (str) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XML_CONVERSION, - JS_GetStringBytes(str)); - } - return NULL; -} - -static JSBool -Append(JSContext *cx, JSXML *list, JSXML *kid); - -static JSObject * -ToXMLList(JSContext *cx, jsval v) -{ - JSObject *obj, *listobj; - JSXML *xml, *list, *kid; - JSClass *clasp; - JSString *str; - uint32 i, length; - - if (JSVAL_IS_PRIMITIVE(v)) { - if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) - goto bad; - } else { - obj = JSVAL_TO_OBJECT(v); - if (OBJECT_IS_XML(cx, obj)) { - xml = (JSXML *) JS_GetPrivate(cx, obj); - if (xml->xml_class != JSXML_CLASS_LIST) { - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return NULL; - list = (JSXML *) JS_GetPrivate(cx, listobj); - if (!Append(cx, list, xml)) - return NULL; - return listobj; - } - return obj; - } - - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) { - JS_ASSERT(0); - } - - if (clasp != &js_StringClass && - clasp != &js_NumberClass && - clasp != &js_BooleanClass) { - goto bad; - } - } - - str = js_ValueToString(cx, v); - if (!str) - return NULL; - if (IS_EMPTY(str)) { - xml = NULL; - length = 0; - } else { - if (!JS_EnterLocalRootScope(cx)) - return NULL; - xml = ParseXMLSource(cx, str); - if (!xml) { - JS_LeaveLocalRootScope(cx); - return NULL; - } - length = JSXML_LENGTH(xml); - } - - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (listobj) { - list = (JSXML *) JS_GetPrivate(cx, listobj); - for (i = 0; i < length; i++) { - kid = OrphanXMLChild(cx, xml, i); - if (!kid) - return NULL; - if (!Append(cx, list, kid)) { - listobj = NULL; - break; - } - } - } - - if (xml) - JS_LeaveLocalRootScope(cx); - return listobj; - -bad: - str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, v, NULL); - if (str) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XMLLIST_CONVERSION, - JS_GetStringBytes(str)); - } - return NULL; -} - -/* - * ECMA-357 10.2.1 Steps 5-7 pulled out as common subroutines of XMLToXMLString - * and their library-public js_* counterparts. The guts of MakeXMLCDataString, - * MakeXMLCommentString, and MakeXMLPIString are further factored into a common - * MakeXMLSpecialString subroutine. - * - * These functions take ownership of sb->base, if sb is non-null, in all cases - * of success or failure. - */ -static JSString * -MakeXMLSpecialString(JSContext *cx, JSStringBuffer *sb, - JSString *str, JSString *str2, - const jschar *prefix, size_t prefixlength, - const jschar *suffix, size_t suffixlength) -{ - JSStringBuffer localSB; - size_t length, length2, newlength; - jschar *bp, *base; - - if (!sb) { - sb = &localSB; - js_InitStringBuffer(sb); - } - - length = JSSTRING_LENGTH(str); - length2 = str2 ? JSSTRING_LENGTH(str2) : 0; - newlength = STRING_BUFFER_OFFSET(sb) + - prefixlength + length + ((length2 != 0) ? 1 + length2 : 0) + - suffixlength; - bp = base = (jschar *) - JS_realloc(cx, sb->base, (newlength + 1) * sizeof(jschar)); - if (!bp) { - js_FinishStringBuffer(sb); - return NULL; - } - - bp += STRING_BUFFER_OFFSET(sb); - js_strncpy(bp, prefix, prefixlength); - bp += prefixlength; - js_strncpy(bp, JSSTRING_CHARS(str), length); - bp += length; - if (length2 != 0) { - *bp++ = (jschar) ' '; - js_strncpy(bp, JSSTRING_CHARS(str2), length2); - bp += length2; - } - js_strncpy(bp, suffix, suffixlength); - bp[suffixlength] = 0; - - str = js_NewString(cx, base, newlength, 0); - if (!str) - free(base); - return str; -} - -static JSString * -MakeXMLCDATAString(JSContext *cx, JSStringBuffer *sb, JSString *str) -{ - static const jschar cdata_prefix_ucNstr[] = {'<', '!', '[', - 'C', 'D', 'A', 'T', 'A', - '['}; - static const jschar cdata_suffix_ucNstr[] = {']', ']', '>'}; - - return MakeXMLSpecialString(cx, sb, str, NULL, - cdata_prefix_ucNstr, 9, - cdata_suffix_ucNstr, 3); -} - -static JSString * -MakeXMLCommentString(JSContext *cx, JSStringBuffer *sb, JSString *str) -{ - static const jschar comment_prefix_ucNstr[] = {'<', '!', '-', '-'}; - static const jschar comment_suffix_ucNstr[] = {'-', '-', '>'}; - - return MakeXMLSpecialString(cx, sb, str, NULL, - comment_prefix_ucNstr, 4, - comment_suffix_ucNstr, 3); -} - -static JSString * -MakeXMLPIString(JSContext *cx, JSStringBuffer *sb, JSString *name, - JSString *value) -{ - static const jschar pi_prefix_ucNstr[] = {'<', '?'}; - static const jschar pi_suffix_ucNstr[] = {'?', '>'}; - - return MakeXMLSpecialString(cx, sb, name, value, - pi_prefix_ucNstr, 2, - pi_suffix_ucNstr, 2); -} - -/* - * ECMA-357 10.2.1 17(d-g) pulled out into a common subroutine that appends - * equals, a double quote, an attribute value, and a closing double quote. - */ -static void -AppendAttributeValue(JSContext *cx, JSStringBuffer *sb, JSString *valstr) -{ - js_AppendCString(sb, "=\""); - valstr = js_EscapeAttributeValue(cx, valstr); - if (!valstr) { - free(sb->base); - sb->base = STRING_BUFFER_ERROR_BASE; - return; - } - js_AppendJSString(sb, valstr); - js_AppendChar(sb, '"'); -} - -/* - * ECMA-357 10.2.1.1 EscapeElementValue helper method. - * - * This function takes ownership of sb->base, if sb is non-null, in all cases - * of success or failure. - */ -static JSString * -EscapeElementValue(JSContext *cx, JSStringBuffer *sb, JSString *str) -{ - size_t length, newlength; - const jschar *cp, *start, *end; - jschar c; - - length = newlength = JSSTRING_LENGTH(str); - for (cp = start = JSSTRING_CHARS(str), end = cp + length; cp < end; cp++) { - c = *cp; - if (c == '<' || c == '>') - newlength += 3; - else if (c == '&') - newlength += 4; - - if (newlength < length) { - JS_ReportOutOfMemory(cx); - return NULL; - } - } - if ((sb && STRING_BUFFER_OFFSET(sb) != 0) || newlength > length) { - JSStringBuffer localSB; - if (!sb) { - sb = &localSB; - js_InitStringBuffer(sb); - } - if (!sb->grow(sb, newlength)) { - JS_ReportOutOfMemory(cx); - return NULL; - } - for (cp = start; cp < end; cp++) { - c = *cp; - if (c == '<') - js_AppendCString(sb, js_lt_entity_str); - else if (c == '>') - js_AppendCString(sb, js_gt_entity_str); - else if (c == '&') - js_AppendCString(sb, js_amp_entity_str); - else - js_AppendChar(sb, c); - } - JS_ASSERT(STRING_BUFFER_OK(sb)); - str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb), 0); - if (!str) - js_FinishStringBuffer(sb); - } - return str; -} - -/* - * ECMA-357 10.2.1.2 EscapeAttributeValue helper method. - * This function takes ownership of sb->base, if sb is non-null, in all cases. - */ -static JSString * -EscapeAttributeValue(JSContext *cx, JSStringBuffer *sb, JSString *str) -{ - size_t length, newlength; - const jschar *cp, *start, *end; - jschar c; - - length = newlength = JSSTRING_LENGTH(str); - for (cp = start = JSSTRING_CHARS(str), end = cp + length; cp < end; cp++) { - c = *cp; - if (c == '"') - newlength += 5; - else if (c == '<') - newlength += 3; - else if (c == '&' || c == '\n' || c == '\r' || c == '\t') - newlength += 4; - - if (newlength < length) { - JS_ReportOutOfMemory(cx); - return NULL; - } - } - if ((sb && STRING_BUFFER_OFFSET(sb) != 0) || newlength > length) { - JSStringBuffer localSB; - if (!sb) { - sb = &localSB; - js_InitStringBuffer(sb); - } - if (!sb->grow(sb, newlength)) { - JS_ReportOutOfMemory(cx); - return NULL; - } - for (cp = start; cp < end; cp++) { - c = *cp; - if (c == '"') - js_AppendCString(sb, js_quot_entity_str); - else if (c == '<') - js_AppendCString(sb, js_lt_entity_str); - else if (c == '&') - js_AppendCString(sb, js_amp_entity_str); - else if (c == '\n') - js_AppendCString(sb, " "); - else if (c == '\r') - js_AppendCString(sb, " "); - else if (c == '\t') - js_AppendCString(sb, " "); - else - js_AppendChar(sb, c); - } - JS_ASSERT(STRING_BUFFER_OK(sb)); - str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb), 0); - if (!str) - js_FinishStringBuffer(sb); - } - return str; -} - -/* 13.3.5.4 [[GetNamespace]]([InScopeNamespaces]) */ -static JSXMLNamespace * -GetNamespace(JSContext *cx, JSXMLQName *qn, const JSXMLArray *inScopeNSes) -{ - JSXMLNamespace *match, *ns; - uint32 i, n; - jsval argv[2]; - JSObject *nsobj; - - JS_ASSERT(qn->uri); - if (!qn->uri) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XML_NAMESPACE, - qn->prefix - ? js_ValueToPrintableString(cx, - STRING_TO_JSVAL(qn->prefix)) - : js_type_str[JSTYPE_VOID]); - return NULL; - } - - /* Look for a matching namespace in inScopeNSes, if provided. */ - match = NULL; - if (inScopeNSes) { - for (i = 0, n = inScopeNSes->length; i < n; i++) { - ns = XMLARRAY_MEMBER(inScopeNSes, i, JSXMLNamespace); - if (!ns) - continue; - - /* - * Erratum, very tricky, and not specified in ECMA-357 13.3.5.4: - * If we preserve prefixes, we must match null qn->prefix against - * an empty ns->prefix, in order to avoid generating redundant - * prefixed and default namespaces for cases such as: - * - * x = - * print(x.toXMLString()); - * - * Per 10.3.2.1, the namespace attribute in t has an empty string - * prefix (*not* a null prefix), per 10.3.2.1 Step 6(h)(i)(1): - * - * 1. If the [local name] property of a is "xmlns" - * a. Map ns.prefix to the empty string - * - * But t's name has a null prefix in this implementation, meaning - * *undefined*, per 10.3.2.1 Step 6(c)'s NOTE (which refers to - * the http://www.w3.org/TR/xml-infoset/ spec, item 2.2.3, without - * saying how "no value" maps to an ECMA-357 value -- but it must - * map to the *undefined* prefix value). - * - * Since "" != undefined (or null, in the current implementation) - * the ECMA-357 spec will fail to match in [[GetNamespace]] called - * on t with argument {} U {(prefix="", uri="http://foo.com")}. - * This spec bug leads to ToXMLString results that duplicate the - * declared namespace. - */ - if (!js_CompareStrings(ns->uri, qn->uri) && - (ns->prefix == qn->prefix || - ((ns->prefix && qn->prefix) - ? !js_CompareStrings(ns->prefix, qn->prefix) - : IS_EMPTY(ns->prefix ? ns->prefix : qn->prefix)))) { - match = ns; - break; - } - } - } - - /* If we didn't match, make a new namespace from qn. */ - if (!match) { - argv[0] = qn->prefix ? STRING_TO_JSVAL(qn->prefix) : JSVAL_VOID; - argv[1] = STRING_TO_JSVAL(qn->uri); - nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, - 2, argv); - if (!nsobj) - return NULL; - match = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); - } - return match; -} - -static JSString * -GeneratePrefix(JSContext *cx, JSString *uri, JSXMLArray *decls) -{ - const jschar *cp, *start, *end; - size_t length, newlength, offset; - uint32 i, n, m, serial; - jschar *bp, *dp; - JSBool done; - JSXMLNamespace *ns; - JSString *prefix; - - JS_ASSERT(!IS_EMPTY(uri)); - - /* - * Try peeling off the last filename suffix or pathname component till - * we have a valid XML name. This heuristic will prefer "xul" given - * ".../there.is.only.xul", "xbl" given ".../xbl", and "xbl2" given any - * likely URI of the form ".../xbl2/2005". - */ - start = JSSTRING_CHARS(uri); - cp = end = start + JSSTRING_LENGTH(uri); - while (--cp > start) { - if (*cp == '.' || *cp == '/' || *cp == ':') { - ++cp; - if (IsXMLName(cp, PTRDIFF(end, cp, jschar))) - break; - end = --cp; - } - } - length = PTRDIFF(end, cp, jschar); - - /* - * Now search through decls looking for a collision. If we collide with - * an existing prefix, start tacking on a hyphen and a serial number. - */ - serial = 0; - bp = NULL; -#ifdef __GNUC__ /* suppress bogus gcc warnings */ - newlength = 0; -#endif - do { - done = JS_TRUE; - for (i = 0, n = decls->length; i < n; i++) { - ns = XMLARRAY_MEMBER(decls, i, JSXMLNamespace); - if (ns && ns->prefix && - JSSTRING_LENGTH(ns->prefix) == length && - !memcmp(JSSTRING_CHARS(ns->prefix), cp, - length * sizeof(jschar))) { - if (!bp) { - newlength = length + 2 + (size_t) log10(n); - bp = (jschar *) - JS_malloc(cx, (newlength + 1) * sizeof(jschar)); - if (!bp) - return NULL; - js_strncpy(bp, cp, length); - } - - ++serial; - JS_ASSERT(serial <= n); - dp = bp + length + 2 + (size_t) log10(serial); - *dp = 0; - for (m = serial; m != 0; m /= 10) - *--dp = (jschar)('0' + m % 10); - *--dp = '-'; - JS_ASSERT(dp == bp + length); - - done = JS_FALSE; - break; - } - } - } while (!done); - - if (!bp) { - offset = PTRDIFF(cp, start, jschar); - prefix = js_NewDependentString(cx, uri, offset, length, 0); - } else { - prefix = js_NewString(cx, bp, newlength, 0); - if (!prefix) - JS_free(cx, bp); - } - return prefix; -} - -static JSBool -namespace_match(const void *a, const void *b) -{ - const JSXMLNamespace *nsa = (const JSXMLNamespace *) a; - const JSXMLNamespace *nsb = (const JSXMLNamespace *) b; - - if (nsb->prefix) - return nsa->prefix && !js_CompareStrings(nsa->prefix, nsb->prefix); - return !js_CompareStrings(nsa->uri, nsb->uri); -} - -/* ECMA-357 10.2.1 and 10.2.2 */ -static JSString * -XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, - uintN indentLevel) -{ - JSBool pretty, indentKids; - JSStringBuffer sb; - JSString *str, *prefix, *kidstr; - JSXMLArrayCursor cursor; - uint32 i, n; - JSXMLArray empty, decls, ancdecls; - JSXMLNamespace *ns, *ns2; - uintN nextIndentLevel; - JSXML *attr, *kid; - - if (!GetBooleanXMLSetting(cx, js_prettyPrinting_str, &pretty)) - return NULL; - - js_InitStringBuffer(&sb); - if (pretty) - js_RepeatChar(&sb, ' ', indentLevel); - str = NULL; - - switch (xml->xml_class) { - case JSXML_CLASS_TEXT: - /* Step 4. */ - if (pretty) { - str = ChompXMLWhitespace(cx, xml->xml_value); - if (!str) - return NULL; - } else { - str = xml->xml_value; - } - return EscapeElementValue(cx, &sb, str); - - case JSXML_CLASS_ATTRIBUTE: - /* Step 5. */ - return EscapeAttributeValue(cx, &sb, xml->xml_value); - - case JSXML_CLASS_COMMENT: - /* Step 6. */ - return MakeXMLCommentString(cx, &sb, xml->xml_value); - - case JSXML_CLASS_PROCESSING_INSTRUCTION: - /* Step 7. */ - return MakeXMLPIString(cx, &sb, xml->name->localName, xml->xml_value); - - case JSXML_CLASS_LIST: - /* ECMA-357 10.2.2. */ - XMLArrayCursorInit(&cursor, &xml->xml_kids); - i = 0; - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (pretty && i != 0) - js_AppendChar(&sb, '\n'); - - kidstr = XMLToXMLString(cx, kid, ancestorNSes, indentLevel); - if (!kidstr) - break; - - js_AppendJSString(&sb, kidstr); - ++i; - } - XMLArrayCursorFinish(&cursor); - if (kid) - goto list_out; - - if (!sb.base) { - if (!STRING_BUFFER_OK(&sb)) { - JS_ReportOutOfMemory(cx); - return NULL; - } - return cx->runtime->emptyString; - } - - str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb), 0); - list_out: - if (!str) - js_FinishStringBuffer(&sb); - return str; - - default:; - } - - /* After this point, control must flow through label out: to exit. */ - if (!JS_EnterLocalRootScope(cx)) - return NULL; - - /* ECMA-357 10.2.1 step 8 onward: handle ToXMLString on an XML element. */ - if (!ancestorNSes) { - XMLArrayInit(cx, &empty, 0); - ancestorNSes = ∅ - } - XMLArrayInit(cx, &decls, 0); - ancdecls.capacity = 0; - - /* Clone in-scope namespaces not in ancestorNSes into decls. */ - XMLArrayCursorInit(&cursor, &xml->xml_namespaces); - while ((ns = (JSXMLNamespace *) XMLArrayCursorNext(&cursor)) != NULL) { - if (!ns->declared) - continue; - if (!XMLARRAY_HAS_MEMBER(ancestorNSes, ns, namespace_identity)) { - /* NOTE: may want to exclude unused namespaces here. */ - ns2 = js_NewXMLNamespace(cx, ns->prefix, ns->uri, JS_TRUE); - if (!ns2 || !XMLARRAY_APPEND(cx, &decls, ns2)) - break; - } - } - XMLArrayCursorFinish(&cursor); - if (ns) - goto out; - - /* - * Union ancestorNSes and decls into ancdecls. Note that ancdecls does - * not own its member references. In the spec, ancdecls has no name, but - * is always written out as (AncestorNamespaces U namespaceDeclarations). - */ - if (!XMLArrayInit(cx, &ancdecls, ancestorNSes->length + decls.length)) - goto out; - for (i = 0, n = ancestorNSes->length; i < n; i++) { - ns2 = XMLARRAY_MEMBER(ancestorNSes, i, JSXMLNamespace); - if (!ns2) - continue; - JS_ASSERT(!XMLARRAY_HAS_MEMBER(&decls, ns2, namespace_identity)); - if (!XMLARRAY_APPEND(cx, &ancdecls, ns2)) - goto out; - } - for (i = 0, n = decls.length; i < n; i++) { - ns2 = XMLARRAY_MEMBER(&decls, i, JSXMLNamespace); - if (!ns2) - continue; - JS_ASSERT(!XMLARRAY_HAS_MEMBER(&ancdecls, ns2, namespace_identity)); - if (!XMLARRAY_APPEND(cx, &ancdecls, ns2)) - goto out; - } - - /* Step 11, except we don't clone ns unless its prefix is undefined. */ - ns = GetNamespace(cx, xml->name, &ancdecls); - if (!ns) - goto out; - - /* Step 12 (NULL means *undefined* here), plus the deferred ns cloning. */ - if (!ns->prefix) { - /* - * Create a namespace prefix that isn't used by any member of decls. - * Assign the new prefix to a copy of ns. Flag this namespace as if - * it were declared, for assertion-testing's sake later below. - * - * Erratum: if ns->prefix and xml->name are both null (*undefined* in - * ECMA-357), we know that xml was named using the default namespace - * (proof: see GetNamespace and the Namespace constructor called with - * two arguments). So we ought not generate a new prefix here, when - * we can declare ns as the default namespace for xml. - * - * This helps descendants inherit the namespace instead of redundantly - * redeclaring it with generated prefixes in each descendant. - */ - if (!xml->name->prefix) { - prefix = cx->runtime->emptyString; - } else { - prefix = GeneratePrefix(cx, ns->uri, &ancdecls); - if (!prefix) - goto out; - } - ns = js_NewXMLNamespace(cx, prefix, ns->uri, JS_TRUE); - if (!ns) - goto out; - - /* - * If the xml->name was unprefixed, we must remove any declared default - * namespace from decls before appending ns. How can you get a default - * namespace in decls that doesn't match the one from name? Apparently - * by calling x.setNamespace(ns) where ns has no prefix. The other way - * to fix this is to update x's in-scope namespaces when setNamespace - * is called, but that's not specified by ECMA-357. - * - * Likely Erratum here, depending on whether the lack of update to x's - * in-scope namespace in XML.prototype.setNamespace (13.4.4.36) is an - * erratum or not. Note that changing setNamespace to update the list - * of in-scope namespaces will change x.namespaceDeclarations(). - */ - if (IS_EMPTY(prefix)) { - i = XMLArrayFindMember(&decls, ns, namespace_match); - if (i != XML_NOT_FOUND) - XMLArrayDelete(cx, &decls, i, JS_TRUE); - } - - /* - * In the spec, ancdecls has no name, but is always written out as - * (AncestorNamespaces U namespaceDeclarations). Since we compute - * that union in ancdecls, any time we append a namespace strong - * ref to decls, we must also append a weak ref to ancdecls. Order - * matters here: code at label out: releases strong refs in decls. - */ - if (!XMLARRAY_APPEND(cx, &ancdecls, ns) || - !XMLARRAY_APPEND(cx, &decls, ns)) { - goto out; - } - } - - /* Format the element or point-tag into sb. */ - js_AppendChar(&sb, '<'); - - if (ns->prefix && !IS_EMPTY(ns->prefix)) { - js_AppendJSString(&sb, ns->prefix); - js_AppendChar(&sb, ':'); - } - js_AppendJSString(&sb, xml->name->localName); - - /* - * Step 16 makes a union to avoid writing two loops in step 17, to share - * common attribute value appending spec-code. We prefer two loops for - * faster code and less data overhead. - */ - - /* Step 17(c): append XML namespace declarations. */ - XMLArrayCursorInit(&cursor, &decls); - while ((ns2 = (JSXMLNamespace *) XMLArrayCursorNext(&cursor)) != NULL) { - JS_ASSERT(ns2->declared); - - js_AppendCString(&sb, " xmlns"); - - /* 17(c)(ii): NULL means *undefined* here. */ - if (!ns2->prefix) { - prefix = GeneratePrefix(cx, ns2->uri, &ancdecls); - if (!prefix) - break; - ns2->prefix = prefix; - } - - /* 17(c)(iii). */ - if (!IS_EMPTY(ns2->prefix)) { - js_AppendChar(&sb, ':'); - js_AppendJSString(&sb, ns2->prefix); - } - - /* 17(d-g). */ - AppendAttributeValue(cx, &sb, ns2->uri); - } - XMLArrayCursorFinish(&cursor); - if (ns2) - goto out; - - /* Step 17(b): append attributes. */ - XMLArrayCursorInit(&cursor, &xml->xml_attrs); - while ((attr = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - js_AppendChar(&sb, ' '); - ns2 = GetNamespace(cx, attr->name, &ancdecls); - if (!ns2) - break; - - /* 17(b)(ii): NULL means *undefined* here. */ - if (!ns2->prefix) { - prefix = GeneratePrefix(cx, ns2->uri, &ancdecls); - if (!prefix) - break; - - /* Again, we avoid copying ns2 until we know it's prefix-less. */ - ns2 = js_NewXMLNamespace(cx, prefix, ns2->uri, JS_TRUE); - if (!ns2) - break; - - /* - * In the spec, ancdecls has no name, but is always written out as - * (AncestorNamespaces U namespaceDeclarations). Since we compute - * that union in ancdecls, any time we append a namespace strong - * ref to decls, we must also append a weak ref to ancdecls. Order - * matters here: code at label out: releases strong refs in decls. - */ - if (!XMLARRAY_APPEND(cx, &ancdecls, ns2) || - !XMLARRAY_APPEND(cx, &decls, ns2)) { - break; - } - } - - /* 17(b)(iii). */ - if (!IS_EMPTY(ns2->prefix)) { - js_AppendJSString(&sb, ns2->prefix); - js_AppendChar(&sb, ':'); - } - - /* 17(b)(iv). */ - js_AppendJSString(&sb, attr->name->localName); - - /* 17(d-g). */ - AppendAttributeValue(cx, &sb, attr->xml_value); - } - XMLArrayCursorFinish(&cursor); - if (attr) - goto out; - - /* Step 18: handle point tags. */ - n = xml->xml_kids.length; - if (n == 0) { - js_AppendCString(&sb, "/>"); - } else { - /* Steps 19 through 25: handle element content, and open the end-tag. */ - js_AppendChar(&sb, '>'); - indentKids = n > 1 || - (n == 1 && - (kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML)) && - kid->xml_class != JSXML_CLASS_TEXT); - - if (pretty && indentKids) { - if (!GetUint32XMLSetting(cx, js_prettyIndent_str, &i)) - goto out; - nextIndentLevel = indentLevel + i; - } else { - nextIndentLevel = 0; - } - - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (pretty && indentKids) - js_AppendChar(&sb, '\n'); - - kidstr = XMLToXMLString(cx, kid, &ancdecls, nextIndentLevel); - if (!kidstr) - break; - - js_AppendJSString(&sb, kidstr); - } - XMLArrayCursorFinish(&cursor); - if (kid) - goto out; - - if (pretty && indentKids) { - js_AppendChar(&sb, '\n'); - js_RepeatChar(&sb, ' ', indentLevel); - } - js_AppendCString(&sb, "prefix && !IS_EMPTY(ns->prefix)) { - js_AppendJSString(&sb, ns->prefix); - js_AppendChar(&sb, ':'); - } - - /* Step 27. */ - js_AppendJSString(&sb, xml->name->localName); - js_AppendChar(&sb, '>'); - } - - if (!STRING_BUFFER_OK(&sb)) { - JS_ReportOutOfMemory(cx); - goto out; - } - - str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb), 0); -out: - JS_LeaveLocalRootScope(cx); - if (!str && STRING_BUFFER_OK(&sb)) - js_FinishStringBuffer(&sb); - XMLArrayFinish(cx, &decls); - if (ancdecls.capacity != 0) - XMLArrayFinish(cx, &ancdecls); - return str; -} - -/* ECMA-357 10.2 */ -static JSString * -ToXMLString(JSContext *cx, jsval v) -{ - JSObject *obj; - JSString *str; - JSXML *xml; - - if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XML_CONVERSION, - js_type_str[JSVAL_IS_NULL(v) - ? JSTYPE_NULL - : JSTYPE_VOID]); - return NULL; - } - - if (JSVAL_IS_BOOLEAN(v) || JSVAL_IS_NUMBER(v)) - return js_ValueToString(cx, v); - - if (JSVAL_IS_STRING(v)) - return EscapeElementValue(cx, NULL, JSVAL_TO_STRING(v)); - - obj = JSVAL_TO_OBJECT(v); - if (!OBJECT_IS_XML(cx, obj)) { - if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v)) - return NULL; - str = js_ValueToString(cx, v); - if (!str) - return NULL; - return EscapeElementValue(cx, NULL, str); - } - - /* Handle non-element cases in this switch, returning from each case. */ - xml = (JSXML *) JS_GetPrivate(cx, obj); - return XMLToXMLString(cx, xml, NULL, 0); -} - -static JSXMLQName * -ToAttributeName(JSContext *cx, jsval v) -{ - JSString *name, *uri, *prefix; - JSObject *obj; - JSClass *clasp; - JSXMLQName *qn; - JSTempValueRooter tvr; - - if (JSVAL_IS_STRING(v)) { - name = JSVAL_TO_STRING(v); - uri = prefix = cx->runtime->emptyString; - } else { - if (JSVAL_IS_PRIMITIVE(v)) { - name = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, v, NULL); - if (name) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XML_ATTR_NAME, - JS_GetStringBytes(name)); - } - return NULL; - } - - obj = JSVAL_TO_OBJECT(v); - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp == &js_AttributeNameClass) - return (JSXMLQName *) JS_GetPrivate(cx, obj); - - if (clasp == &js_QNameClass.base) { - qn = (JSXMLQName *) JS_GetPrivate(cx, obj); - uri = qn->uri; - prefix = qn->prefix; - name = qn->localName; - } else { - if (clasp == &js_AnyNameClass) { - name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); - } else { - name = js_ValueToString(cx, v); - if (!name) - return NULL; - } - uri = prefix = cx->runtime->emptyString; - } - } - - qn = js_NewXMLQName(cx, uri, prefix, name); - if (!qn) - return NULL; - - /* - * Temp and local root scope APIs take GC-thing pointers tagged as jsvals - * and blindly untag. Since qn is a GC-thing pointer, we can treat it as - * an object pointer. - */ - JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(qn), &tvr); - obj = js_GetAttributeNameObject(cx, qn); - JS_POP_TEMP_ROOT(cx, &tvr); - if (!obj) - return NULL; - return qn; -} - -static JSXMLQName * -ToXMLName(JSContext *cx, jsval v, jsid *funidp) -{ - JSString *name; - JSObject *obj; - JSClass *clasp; - uint32 index; - JSXMLQName *qn; - JSAtom *atom; - - if (JSVAL_IS_STRING(v)) { - name = JSVAL_TO_STRING(v); - } else { - if (JSVAL_IS_PRIMITIVE(v)) { - name = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, v, NULL); - if (name) - goto bad; - return NULL; - } - - obj = JSVAL_TO_OBJECT(v); - clasp = OBJ_GET_CLASS(cx, obj); - if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass.base) - goto out; - if (clasp == &js_AnyNameClass) { - name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); - goto construct; - } - name = js_ValueToString(cx, v); - if (!name) - return NULL; - } - - /* - * ECMA-357 10.6.1 step 1 seems to be incorrect. The spec says: - * - * 1. If ToString(ToNumber(P)) == ToString(P), throw a TypeError exception - * - * First, _P_ should be _s_, to refer to the given string. - * - * Second, why does ToXMLName applied to the string type throw TypeError - * only for numeric literals without any leading or trailing whitespace? - * - * If the idea is to reject uint32 property names, then the check needs to - * be stricter, to exclude hexadecimal and floating point literals. - */ - if (js_IdIsIndex(STRING_TO_JSVAL(name), &index)) - goto bad; - - if (*JSSTRING_CHARS(name) == '@') { - name = js_NewDependentString(cx, name, 1, JSSTRING_LENGTH(name) - 1, 0); - if (!name) - return NULL; - *funidp = 0; - return ToAttributeName(cx, STRING_TO_JSVAL(name)); - } - -construct: - v = STRING_TO_JSVAL(name); - obj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &v); - if (!obj) - return NULL; - -out: - qn = (JSXMLQName *) JS_GetPrivate(cx, obj); - atom = cx->runtime->atomState.lazy.functionNamespaceURIAtom; - if (qn->uri && atom && - (qn->uri == ATOM_TO_STRING(atom) || - !js_CompareStrings(qn->uri, ATOM_TO_STRING(atom)))) { - if (!JS_ValueToId(cx, STRING_TO_JSVAL(qn->localName), funidp)) - return NULL; - } else { - *funidp = 0; - } - return qn; - -bad: - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XML_NAME, - js_ValueToPrintableString(cx, STRING_TO_JSVAL(name))); - return NULL; -} - -/* ECMA-357 9.1.1.13 XML [[AddInScopeNamespace]]. */ -static JSBool -AddInScopeNamespace(JSContext *cx, JSXML *xml, JSXMLNamespace *ns) -{ - JSXMLNamespace *match, *ns2; - uint32 i, n, m; - - if (xml->xml_class != JSXML_CLASS_ELEMENT) - return JS_TRUE; - - /* NULL means *undefined* here -- see ECMA-357 9.1.1.13 step 2. */ - if (!ns->prefix) { - match = NULL; - for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { - ns2 = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace); - if (ns2 && !js_CompareStrings(ns2->uri, ns->uri)) { - match = ns2; - break; - } - } - if (!match && !XMLARRAY_ADD_MEMBER(cx, &xml->xml_namespaces, n, ns)) - return JS_FALSE; - } else { - if (IS_EMPTY(ns->prefix) && IS_EMPTY(xml->name->uri)) - return JS_TRUE; - match = NULL; -#ifdef __GNUC__ /* suppress bogus gcc warnings */ - m = XML_NOT_FOUND; -#endif - for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { - ns2 = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace); - if (ns2 && ns2->prefix && - !js_CompareStrings(ns2->prefix, ns->prefix)) { - match = ns2; - m = i; - break; - } - } - if (match && js_CompareStrings(match->uri, ns->uri)) { - ns2 = XMLARRAY_DELETE(cx, &xml->xml_namespaces, m, JS_TRUE, - JSXMLNamespace); - JS_ASSERT(ns2 == match); - match->prefix = NULL; - if (!AddInScopeNamespace(cx, xml, match)) - return JS_FALSE; - } - if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) - return JS_FALSE; - } - - /* OPTION: enforce that descendants have superset namespaces. */ - return JS_TRUE; -} - -/* ECMA-357 9.2.1.6 XMLList [[Append]]. */ -static JSBool -Append(JSContext *cx, JSXML *list, JSXML *xml) -{ - uint32 i, j, k, n; - JSXML *kid; - - JS_ASSERT(list->xml_class == JSXML_CLASS_LIST); - i = list->xml_kids.length; - n = 1; - if (xml->xml_class == JSXML_CLASS_LIST) { - list->xml_target = xml->xml_target; - list->xml_targetprop = xml->xml_targetprop; - n = JSXML_LENGTH(xml); - k = i + n; - if (!XMLArraySetCapacity(cx, &list->xml_kids, k)) - return JS_FALSE; - for (j = 0; j < n; j++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, j, JSXML); - if (kid) - XMLARRAY_SET_MEMBER(&list->xml_kids, i + j, kid); - } - return JS_TRUE; - } - - list->xml_target = xml->parent; - if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) - list->xml_targetprop = NULL; - else - list->xml_targetprop = xml->name; - if (!XMLARRAY_ADD_MEMBER(cx, &list->xml_kids, i, xml)) - return JS_FALSE; - return JS_TRUE; -} - -/* ECMA-357 9.1.1.7 XML [[DeepCopy]] and 9.2.1.7 XMLList [[DeepCopy]]. */ -static JSXML * -DeepCopyInLRS(JSContext *cx, JSXML *xml, uintN flags); - -static JSXML * -DeepCopy(JSContext *cx, JSXML *xml, JSObject *obj, uintN flags) -{ - JSXML *copy; - JSBool ok; - - /* Our caller may not be protecting newborns with a local root scope. */ - if (!JS_EnterLocalRootScope(cx)) - return NULL; - copy = DeepCopyInLRS(cx, xml, flags); - if (copy) { - if (obj) { - /* Caller provided the object for this copy, hook 'em up. */ - ok = JS_SetPrivate(cx, obj, copy); - if (ok) - copy->object = obj; - } else { - ok = js_GetXMLObject(cx, copy) != NULL; - } - if (!ok) - copy = NULL; - } - JS_LeaveLocalRootScope(cx); - return copy; -} - -/* - * (i) We must be in a local root scope (InLRS). - * (ii) parent must have a rooted object. - * (iii) from's owning object must be locked if not thread-local. - */ -static JSBool -DeepCopySetInLRS(JSContext *cx, JSXMLArray *from, JSXMLArray *to, JSXML *parent, - uintN flags) -{ - uint32 j, n; - JSXMLArrayCursor cursor; - JSBool ok; - JSXML *kid, *kid2; - JSString *str; - - JS_ASSERT(cx->localRootStack); - - n = from->length; - if (!XMLArraySetCapacity(cx, to, n)) - return JS_FALSE; - - XMLArrayCursorInit(&cursor, from); - j = 0; - ok = JS_TRUE; - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if ((flags & XSF_IGNORE_COMMENTS) && - kid->xml_class == JSXML_CLASS_COMMENT) { - continue; - } - if ((flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS) && - kid->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) { - continue; - } - if ((flags & XSF_IGNORE_WHITESPACE) && - (kid->xml_flags & XMLF_WHITESPACE_TEXT)) { - continue; - } - kid2 = DeepCopyInLRS(cx, kid, flags); - if (!kid2) { - to->length = j; - ok = JS_FALSE; - break; - } - - if ((flags & XSF_IGNORE_WHITESPACE) && - n > 1 && kid2->xml_class == JSXML_CLASS_TEXT) { - str = ChompXMLWhitespace(cx, kid2->xml_value); - if (!str) { - to->length = j; - ok = JS_FALSE; - break; - } - kid2->xml_value = str; - } - - XMLARRAY_SET_MEMBER(to, j, kid2); - ++j; - if (parent->xml_class != JSXML_CLASS_LIST) - kid2->parent = parent; - } - XMLArrayCursorFinish(&cursor); - if (!ok) - return JS_FALSE; - - if (j < n) - XMLArrayTrim(to); - return JS_TRUE; -} - -static JSXML * -DeepCopyInLRS(JSContext *cx, JSXML *xml, uintN flags) -{ - JSXML *copy; - JSXMLQName *qn; - JSBool ok; - uint32 i, n; - JSXMLNamespace *ns, *ns2; - - /* Our caller must be protecting newborn objects. */ - JS_ASSERT(cx->localRootStack); - - copy = js_NewXML(cx, xml->xml_class); - if (!copy) - return NULL; - qn = xml->name; - if (qn) { - qn = js_NewXMLQName(cx, qn->uri, qn->prefix, qn->localName); - if (!qn) { - ok = JS_FALSE; - goto out; - } - } - copy->name = qn; - copy->xml_flags = xml->xml_flags; - - if (JSXML_HAS_VALUE(xml)) { - copy->xml_value = xml->xml_value; - ok = JS_TRUE; - } else { - ok = DeepCopySetInLRS(cx, &xml->xml_kids, ©->xml_kids, copy, flags); - if (!ok) - goto out; - - if (xml->xml_class == JSXML_CLASS_LIST) { - copy->xml_target = xml->xml_target; - copy->xml_targetprop = xml->xml_targetprop; - } else { - n = xml->xml_namespaces.length; - ok = XMLArraySetCapacity(cx, ©->xml_namespaces, n); - if (!ok) - goto out; - for (i = 0; i < n; i++) { - ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace); - if (!ns) - continue; - ns2 = js_NewXMLNamespace(cx, ns->prefix, ns->uri, ns->declared); - if (!ns2) { - copy->xml_namespaces.length = i; - ok = JS_FALSE; - goto out; - } - XMLARRAY_SET_MEMBER(©->xml_namespaces, i, ns2); - } - - ok = DeepCopySetInLRS(cx, &xml->xml_attrs, ©->xml_attrs, copy, - 0); - if (!ok) - goto out; - } - } - -out: - if (!ok) - return NULL; - return copy; -} - -static void -ReportBadXMLName(JSContext *cx, jsval id) -{ - JSString *name; - - name = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, id, NULL); - if (name) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XML_NAME, - JS_GetStringBytes(name)); - } -} - -/* ECMA-357 9.1.1.4 XML [[DeleteByIndex]]. */ -static JSBool -DeleteByIndex(JSContext *cx, JSXML *xml, jsval id, jsval *vp) -{ - uint32 index; - JSXML *kid; - - if (!js_IdIsIndex(id, &index)) { - ReportBadXMLName(cx, id); - return JS_FALSE; - } - - if (JSXML_HAS_KIDS(xml) && index < xml->xml_kids.length) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); - if (kid) - kid->parent = NULL; - XMLArrayDelete(cx, &xml->xml_kids, index, JS_TRUE); - } - - *vp = JSVAL_TRUE; - return JS_TRUE; -} - -typedef JSBool (*JSXMLNameMatcher)(JSXMLQName *nameqn, JSXML *xml); - -static JSBool -MatchAttrName(JSXMLQName *nameqn, JSXML *attr) -{ - JSXMLQName *attrqn = attr->name; - - return (IS_STAR(nameqn->localName) || - !js_CompareStrings(attrqn->localName, nameqn->localName)) && - (!nameqn->uri || - !js_CompareStrings(attrqn->uri, nameqn->uri)); -} - -static JSBool -MatchElemName(JSXMLQName *nameqn, JSXML *elem) -{ - return (IS_STAR(nameqn->localName) || - (elem->xml_class == JSXML_CLASS_ELEMENT && - !js_CompareStrings(elem->name->localName, nameqn->localName))) && - (!nameqn->uri || - (elem->xml_class == JSXML_CLASS_ELEMENT && - !js_CompareStrings(elem->name->uri, nameqn->uri))); -} - -/* ECMA-357 9.1.1.8 XML [[Descendants]] and 9.2.1.8 XMLList [[Descendants]]. */ -static JSBool -DescendantsHelper(JSContext *cx, JSXML *xml, JSXMLQName *nameqn, JSXML *list) -{ - uint32 i, n; - JSXML *attr, *kid; - - if (xml->xml_class == JSXML_CLASS_ELEMENT && - OBJ_GET_CLASS(cx, nameqn->object) == &js_AttributeNameClass) { - for (i = 0, n = xml->xml_attrs.length; i < n; i++) { - attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); - if (attr && MatchAttrName(nameqn, attr)) { - if (!Append(cx, list, attr)) - return JS_FALSE; - } - } - } - - for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (!kid) - continue; - if (OBJ_GET_CLASS(cx, nameqn->object) != &js_AttributeNameClass && - MatchElemName(nameqn, kid)) { - if (!Append(cx, list, kid)) - return JS_FALSE; - } - if (!DescendantsHelper(cx, kid, nameqn, list)) - return JS_FALSE; - } - return JS_TRUE; -} - -static JSXML * -Descendants(JSContext *cx, JSXML *xml, jsval id) -{ - jsid funid; - JSXMLQName *nameqn; - JSObject *listobj; - JSXML *list, *kid; - uint32 i, n; - JSBool ok; - - nameqn = ToXMLName(cx, id, &funid); - if (!nameqn) - return NULL; - - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return NULL; - list = (JSXML *) JS_GetPrivate(cx, listobj); - if (funid) - return list; - - /* - * Protect nameqn's object and strings from GC by linking list to it - * temporarily. The cx->newborn[GCX_OBJECT] GC root protects listobj, - * which protects list. Any other object allocations occuring beneath - * DescendantsHelper use local roots. - */ - list->name = nameqn; - if (!JS_EnterLocalRootScope(cx)) - return NULL; - if (xml->xml_class == JSXML_CLASS_LIST) { - ok = JS_TRUE; - for (i = 0, n = xml->xml_kids.length; i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - ok = DescendantsHelper(cx, kid, nameqn, list); - if (!ok) - break; - } - } - } else { - ok = DescendantsHelper(cx, xml, nameqn, list); - } - JS_LeaveLocalRootScope(cx); - if (!ok) - return NULL; - list->name = NULL; - return list; -} - -static JSBool -xml_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); - -/* Recursive (JSXML *) parameterized version of Equals. */ -static JSBool -XMLEquals(JSContext *cx, JSXML *xml, JSXML *vxml, JSBool *bp) -{ - JSXMLQName *qn, *vqn; - uint32 i, j, n; - JSXMLArrayCursor cursor, vcursor; - JSXML *kid, *vkid, *attr, *vattr; - JSBool ok; - JSObject *xobj, *vobj; - -retry: - if (xml->xml_class != vxml->xml_class) { - if (xml->xml_class == JSXML_CLASS_LIST && xml->xml_kids.length == 1) { - xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (xml) - goto retry; - } - if (vxml->xml_class == JSXML_CLASS_LIST && vxml->xml_kids.length == 1) { - vxml = XMLARRAY_MEMBER(&vxml->xml_kids, 0, JSXML); - if (vxml) - goto retry; - } - *bp = JS_FALSE; - return JS_TRUE; - } - - qn = xml->name; - vqn = vxml->name; - if (qn) { - *bp = vqn && - !js_CompareStrings(qn->localName, vqn->localName) && - !js_CompareStrings(qn->uri, vqn->uri); - } else { - *bp = vqn == NULL; - } - if (!*bp) - return JS_TRUE; - - if (JSXML_HAS_VALUE(xml)) { - *bp = !js_CompareStrings(xml->xml_value, vxml->xml_value); - } else if (xml->xml_kids.length != vxml->xml_kids.length) { - *bp = JS_FALSE; - } else { - XMLArrayCursorInit(&cursor, &xml->xml_kids); - XMLArrayCursorInit(&vcursor, &vxml->xml_kids); - for (;;) { - kid = (JSXML *) XMLArrayCursorNext(&cursor); - vkid = (JSXML *) XMLArrayCursorNext(&vcursor); - if (!kid || !vkid) { - *bp = !kid && !vkid; - ok = JS_TRUE; - break; - } - xobj = js_GetXMLObject(cx, kid); - vobj = js_GetXMLObject(cx, vkid); - ok = xobj && vobj && - xml_equality(cx, xobj, OBJECT_TO_JSVAL(vobj), bp); - if (!ok || !*bp) - break; - } - XMLArrayCursorFinish(&vcursor); - XMLArrayCursorFinish(&cursor); - if (!ok) - return JS_FALSE; - - if (*bp && xml->xml_class == JSXML_CLASS_ELEMENT) { - n = xml->xml_attrs.length; - if (n != vxml->xml_attrs.length) - *bp = JS_FALSE; - for (i = 0; *bp && i < n; i++) { - attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); - if (!attr) - continue; - j = XMLARRAY_FIND_MEMBER(&vxml->xml_attrs, attr, attr_identity); - if (j == XML_NOT_FOUND) { - *bp = JS_FALSE; - break; - } - vattr = XMLARRAY_MEMBER(&vxml->xml_attrs, j, JSXML); - if (!vattr) - continue; - *bp = !js_CompareStrings(attr->xml_value, vattr->xml_value); - } - } - } - - return JS_TRUE; -} - -/* ECMA-357 9.1.1.9 XML [[Equals]] and 9.2.1.9 XMLList [[Equals]]. */ -static JSBool -Equals(JSContext *cx, JSXML *xml, jsval v, JSBool *bp) -{ - JSObject *vobj; - JSXML *vxml; - - if (JSVAL_IS_PRIMITIVE(v)) { - *bp = JS_FALSE; - if (xml->xml_class == JSXML_CLASS_LIST) { - if (xml->xml_kids.length == 1) { - vxml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (!vxml) - return JS_TRUE; - vobj = js_GetXMLObject(cx, vxml); - if (!vobj) - return JS_FALSE; - return js_XMLObjectOps.equality(cx, vobj, v, bp); - } - if (JSVAL_IS_VOID(v) && xml->xml_kids.length == 0) - *bp = JS_TRUE; - } - } else { - vobj = JSVAL_TO_OBJECT(v); - if (!OBJECT_IS_XML(cx, vobj)) { - *bp = JS_FALSE; - } else { - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - if (!XMLEquals(cx, xml, vxml, bp)) - return JS_FALSE; - } - } - return JS_TRUE; -} - -static JSBool -CheckCycle(JSContext *cx, JSXML *xml, JSXML *kid) -{ - JS_ASSERT(kid->xml_class != JSXML_CLASS_LIST); - - do { - if (xml == kid) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_CYCLIC_VALUE, js_XML_str); - return JS_FALSE; - } - } while ((xml = xml->parent) != NULL); - - return JS_TRUE; -} - -/* ECMA-357 9.1.1.11 XML [[Insert]]. */ -static JSBool -Insert(JSContext *cx, JSXML *xml, uint32 i, jsval v) -{ - uint32 j, n; - JSXML *vxml, *kid; - JSObject *vobj; - JSString *str; - - if (!JSXML_HAS_KIDS(xml)) - return JS_TRUE; - - n = 1; - vxml = NULL; - if (!JSVAL_IS_PRIMITIVE(v)) { - vobj = JSVAL_TO_OBJECT(v); - if (OBJECT_IS_XML(cx, vobj)) { - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - if (vxml->xml_class == JSXML_CLASS_LIST) { - n = vxml->xml_kids.length; - if (n == 0) - return JS_TRUE; - for (j = 0; j < n; j++) { - kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML); - if (!kid) - continue; - if (!CheckCycle(cx, xml, kid)) - return JS_FALSE; - } - } else if (vxml->xml_class == JSXML_CLASS_ELEMENT) { - /* OPTION: enforce that descendants have superset namespaces. */ - if (!CheckCycle(cx, xml, vxml)) - return JS_FALSE; - } - } - } - if (!vxml) { - str = js_ValueToString(cx, v); - if (!str) - return JS_FALSE; - - vxml = js_NewXML(cx, JSXML_CLASS_TEXT); - if (!vxml) - return JS_FALSE; - vxml->xml_value = str; - } - - if (i > xml->xml_kids.length) - i = xml->xml_kids.length; - - if (!XMLArrayInsert(cx, &xml->xml_kids, i, n)) - return JS_FALSE; - - if (vxml->xml_class == JSXML_CLASS_LIST) { - for (j = 0; j < n; j++) { - kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML); - if (!kid) - continue; - kid->parent = xml; - XMLARRAY_SET_MEMBER(&xml->xml_kids, i + j, kid); - - /* OPTION: enforce that descendants have superset namespaces. */ - } - } else { - vxml->parent = xml; - XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml); - } - return JS_TRUE; -} - -static JSBool -IndexToIdVal(JSContext *cx, uint32 index, jsval *idvp) -{ - JSString *str; - - if (index <= JSVAL_INT_MAX) { - *idvp = INT_TO_JSVAL(index); - } else { - str = js_NumberToString(cx, (jsdouble) index); - if (!str) - return JS_FALSE; - *idvp = STRING_TO_JSVAL(str); - } - return JS_TRUE; -} - -/* ECMA-357 9.1.1.12 XML [[Replace]]. */ -static JSBool -Replace(JSContext *cx, JSXML *xml, jsval id, jsval v) -{ - uint32 i, n; - JSXML *vxml, *kid; - JSObject *vobj; - jsval junk; - JSString *str; - - if (!JSXML_HAS_KIDS(xml)) - return JS_TRUE; - - if (!js_IdIsIndex(id, &i)) { - ReportBadXMLName(cx, id); - return JS_FALSE; - } - - /* - * 9.1.1.12 - * [[Replace]] handles _i >= x.[[Length]]_ by incrementing _x.[[Length]_. - * It should therefore constrain callers to pass in _i <= x.[[Length]]_. - */ - n = xml->xml_kids.length; - if (i >= n) { - if (!IndexToIdVal(cx, n, &id)) - return JS_FALSE; - i = n; - } - - vxml = NULL; - if (!JSVAL_IS_PRIMITIVE(v)) { - vobj = JSVAL_TO_OBJECT(v); - if (OBJECT_IS_XML(cx, vobj)) - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - } - - switch (vxml ? vxml->xml_class : JSXML_CLASS_LIMIT) { - case JSXML_CLASS_ELEMENT: - /* OPTION: enforce that descendants have superset namespaces. */ - if (!CheckCycle(cx, xml, vxml)) - return JS_FALSE; - case JSXML_CLASS_COMMENT: - case JSXML_CLASS_PROCESSING_INSTRUCTION: - case JSXML_CLASS_TEXT: - goto do_replace; - - case JSXML_CLASS_LIST: - if (i < n && !DeleteByIndex(cx, xml, id, &junk)) - return JS_FALSE; - if (!Insert(cx, xml, i, v)) - return JS_FALSE; - break; - - default: - str = js_ValueToString(cx, v); - if (!str) - return JS_FALSE; - - vxml = js_NewXML(cx, JSXML_CLASS_TEXT); - if (!vxml) - return JS_FALSE; - vxml->xml_value = str; - - do_replace: - vxml->parent = xml; - if (i < n) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid) - kid->parent = NULL; - } - if (!XMLARRAY_ADD_MEMBER(cx, &xml->xml_kids, i, vxml)) - return JS_FALSE; - break; - } - - return JS_TRUE; -} - -/* Forward declared -- its implementation uses other statics that call it. */ -static JSBool -ResolveValue(JSContext *cx, JSXML *list, JSXML **result); - -/* ECMA-357 9.1.1.3 XML [[Delete]], 9.2.1.3 XML [[Delete]]. */ -static JSBool -DeleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSXML *xml, *kid, *parent; - JSBool isIndex; - JSXMLArray *array; - uint32 length, index, deleteCount; - JSXMLQName *nameqn; - jsid funid; - JSObject *nameobj, *kidobj; - JSXMLNameMatcher matcher; - - xml = (JSXML *) JS_GetPrivate(cx, obj); - isIndex = js_IdIsIndex(id, &index); - if (JSXML_HAS_KIDS(xml)) { - array = &xml->xml_kids; - length = array->length; - } else { - array = NULL; - length = 0; - } - - if (xml->xml_class == JSXML_CLASS_LIST) { - /* ECMA-357 9.2.1.3. */ - if (isIndex && index < length) { - kid = XMLARRAY_MEMBER(array, index, JSXML); - if (!kid) - goto out; - parent = kid->parent; - if (parent) { - JS_ASSERT(parent != xml); - JS_ASSERT(JSXML_HAS_KIDS(parent)); - - if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) { - nameqn = kid->name; - nameobj = js_GetAttributeNameObject(cx, nameqn); - if (!nameobj || !js_GetXMLObject(cx, parent)) - return JS_FALSE; - - id = OBJECT_TO_JSVAL(nameobj); - if (!DeleteProperty(cx, parent->object, id, vp)) - return JS_FALSE; - } else { - index = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL); - JS_ASSERT(index != XML_NOT_FOUND); - if (!IndexToIdVal(cx, index, &id)) - return JS_FALSE; - if (!DeleteByIndex(cx, parent, id, vp)) - return JS_FALSE; - } - } - - XMLArrayDelete(cx, array, index, JS_TRUE); - } else { - for (index = 0; index < length; index++) { - kid = XMLARRAY_MEMBER(array, index, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj || !DeleteProperty(cx, kidobj, id, vp)) - return JS_FALSE; - } - } - } - } else { - /* ECMA-357 9.1.1.3. */ - if (isIndex) { - /* See NOTE in spec: this variation is reserved for future use. */ - ReportBadXMLName(cx, id); - return JS_FALSE; - } - - nameqn = ToXMLName(cx, id, &funid); - if (!nameqn) - return JS_FALSE; - if (funid) - goto out; - nameobj = nameqn->object; - - if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) { - if (xml->xml_class != JSXML_CLASS_ELEMENT) - goto out; - array = &xml->xml_attrs; - length = array->length; - matcher = MatchAttrName; - } else { - matcher = MatchElemName; - } - if (length != 0) { - deleteCount = 0; - for (index = 0; index < length; index++) { - kid = XMLARRAY_MEMBER(array, index, JSXML); - if (kid && matcher(nameqn, kid)) { - kid->parent = NULL; - XMLArrayDelete(cx, array, index, JS_FALSE); - ++deleteCount; - } else if (deleteCount != 0) { - XMLARRAY_SET_MEMBER(array, - index - deleteCount, - array->vector[index]); - } - } - array->length -= deleteCount; - } - } - -out: - *vp = JSVAL_TRUE; - return JS_TRUE; -} - -/* - * Class compatibility mask flag bits stored in xml_methods[i].extra. If XML - * and XMLList are unified (an incompatible change to ECMA-357), then we don't - * need any of this. - */ -#define XML_MASK 0x1 -#define XMLLIST_MASK 0x2 -#define GENERIC_MASK (XML_MASK | XMLLIST_MASK) -#define CLASS_TO_MASK(c) (1 + ((c) == JSXML_CLASS_LIST)) - -static JSBool -GetFunction(JSContext *cx, JSObject *obj, JSXML *xml, jsid id, jsval *vp) -{ - JSFunction *fun; - - do { - /* XXXbe really want a separate scope for function::*. */ - if (!js_GetProperty(cx, obj, id, vp)) - return JS_FALSE; - if (JSVAL_IS_FUNCTION(cx, *vp)) { - if (xml && OBJECT_IS_XML(cx, obj)) { - fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(*vp)); - if (fun->spare && - (fun->spare & CLASS_TO_MASK(xml->xml_class)) == 0) { - /* XML method called on XMLList or vice versa. */ - *vp = JSVAL_VOID; - } - } - break; - } - } while ((obj = OBJ_GET_PROTO(cx, obj)) != NULL); - return JS_TRUE; -} - -static JSBool -SyncInScopeNamespaces(JSContext *cx, JSXML *xml) -{ - JSXMLArray *nsarray; - uint32 i, n; - JSXMLNamespace *ns; - - nsarray = &xml->xml_namespaces; - while ((xml = xml->parent) != NULL) { - for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace); - if (ns && !XMLARRAY_HAS_MEMBER(nsarray, ns, namespace_identity)) { - if (!XMLARRAY_APPEND(cx, nsarray, ns)) - return JS_FALSE; - } - } - } - return JS_TRUE; -} - -/* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */ -static JSBool -GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSXML *xml, *list, *kid; - uint32 index; - JSObject *kidobj, *listobj, *nameobj; - JSXMLQName *nameqn; - jsid funid; - JSBool ok; - JSXMLArrayCursor cursor; - jsval kidval; - JSXMLArray *array; - JSXMLNameMatcher matcher; - - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); - if (!xml) - return JS_TRUE; - -#ifdef __GNUC__ - list = NULL; /* quell GCC overwarning */ -#endif - -retry: - if (xml->xml_class == JSXML_CLASS_LIST) { - /* ECMA-357 9.2.1.1 starts here. */ - if (js_IdIsIndex(id, &index)) { - /* - * Erratum: 9.2 is not completely clear that indexed properties - * correspond to kids, but that's what it seems to say, and it's - * what any sane user would want. - */ - if (index < xml->xml_kids.length) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); - if (!kid) { - *vp = JSVAL_VOID; - return JS_TRUE; - } - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - return JS_FALSE; - - *vp = OBJECT_TO_JSVAL(kidobj); - } else { - *vp = JSVAL_VOID; - } - return JS_TRUE; - } - - nameqn = ToXMLName(cx, id, &funid); - if (!nameqn) - return JS_FALSE; - if (funid) - return GetFunction(cx, obj, xml, funid, vp); - - /* - * Recursion through GetProperty may allocate more list objects, so - * we make use of local root scopes here. Each new allocation will - * push the newborn onto the local root stack. - */ - ok = JS_EnterLocalRootScope(cx); - if (!ok) - return JS_FALSE; - - /* - * NB: nameqn is already protected from GC by cx->newborn[GCX_OBJECT] - * until listobj is created. After that, a local root keeps listobj - * alive, and listobj's private keeps nameqn alive via targetprop. - */ - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) { - ok = JS_FALSE; - } else { - list = (JSXML *) JS_GetPrivate(cx, listobj); - list->xml_target = xml; - - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (kid->xml_class == JSXML_CLASS_ELEMENT) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) { - ok = JS_FALSE; - break; - } - ok = GetProperty(cx, kidobj, id, &kidval); - if (!ok) - break; - kidobj = JSVAL_TO_OBJECT(kidval); - kid = (JSXML *) JS_GetPrivate(cx, kidobj); - if (JSXML_LENGTH(kid) > 0) { - ok = Append(cx, list, kid); - if (!ok) - break; - } - } - } - XMLArrayCursorFinish(&cursor); - } - } else { - /* ECMA-357 9.1.1.1 starts here. */ - if (js_IdIsIndex(id, &index)) { - obj = ToXMLList(cx, OBJECT_TO_JSVAL(obj)); - if (!obj) - return JS_FALSE; - xml = (JSXML *) JS_GetPrivate(cx, obj); - goto retry; - } - - nameqn = ToXMLName(cx, id, &funid); - if (!nameqn) - return JS_FALSE; - if (funid) - return GetFunction(cx, obj, xml, funid, vp); - nameobj = nameqn->object; - - /* - * Recursion through GetProperty may allocate more list objects, so - * we make use of local root scopes here. Each new allocation will - * push the newborn onto the local root stack. - */ - ok = JS_EnterLocalRootScope(cx); - if (!ok) - return JS_FALSE; - - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) { - ok = JS_FALSE; - } else { - list = (JSXML *) JS_GetPrivate(cx, listobj); - list->xml_target = xml; - - if (JSXML_HAS_KIDS(xml)) { - if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) { - array = &xml->xml_attrs; - matcher = MatchAttrName; - } else { - array = &xml->xml_kids; - matcher = MatchElemName; - } - XMLArrayCursorInit(&cursor, array); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (matcher(nameqn, kid)) { - if (array == &xml->xml_kids && - kid->xml_class == JSXML_CLASS_ELEMENT) { - ok = SyncInScopeNamespaces(cx, kid); - if (!ok) - break; - } - ok = Append(cx, list, kid); - if (!ok) - break; - } - } - XMLArrayCursorFinish(&cursor); - } - } - } - - /* Common tail code for list and non-list cases. */ - JS_LeaveLocalRootScope(cx); - if (!ok) - return JS_FALSE; - - /* - * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the given list's - * [[TargetProperty]] to the property that is being appended. This means - * that any use of the internal [[Get]] property returns a list which, - * when used by e.g. [[Insert]] duplicates the last element matched by id. - * See bug 336921. - */ - list->xml_targetprop = nameqn; - *vp = OBJECT_TO_JSVAL(listobj); - return JS_TRUE; -} - -static JSXML * -CopyOnWrite(JSContext *cx, JSXML *xml, JSObject *obj) -{ - JS_ASSERT(xml->object != obj); - - xml = DeepCopy(cx, xml, obj, 0); - if (!xml) - return NULL; - - JS_ASSERT(xml->object == obj); - return xml; -} - -#define CHECK_COPY_ON_WRITE(cx,xml,obj) \ - (xml->object == obj ? xml : CopyOnWrite(cx, xml, obj)) - -static JSString * -KidToString(JSContext *cx, JSXML *xml, uint32 index) -{ - JSXML *kid; - JSObject *kidobj; - - kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); - if (!kid) - return cx->runtime->emptyString; - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - return NULL; - return js_ValueToString(cx, OBJECT_TO_JSVAL(kidobj)); -} - -/* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */ -static JSBool -PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSBool ok, primitiveAssign; - enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; - jsval roots[3]; - JSTempValueRooter tvr; - JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match; - JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj; - JSXMLQName *targetprop, *nameqn, *attrqn; - uint32 index, i, j, k, n, q; - jsval attrval, nsval, junk; - jsid funid; - JSString *left, *right, *space; - JSXMLNamespace *ns; - - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); - if (!xml) - return JS_TRUE; - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - - /* Precompute vxml for 9.2.1.2 2(c)(vii)(2-3) and 2(d) and 9.1.1.2 1. */ - vxml = NULL; - if (!JSVAL_IS_PRIMITIVE(*vp)) { - vobj = JSVAL_TO_OBJECT(*vp); - if (OBJECT_IS_XML(cx, vobj)) - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - } - - /* Control flow after here must exit via label out. */ - ok = JS_EnterLocalRootScope(cx); - if (!ok) - return JS_FALSE; - roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); - roots[ID_ROOT] = id; - roots[VAL_ROOT] = *vp; - JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr); - - if (xml->xml_class == JSXML_CLASS_LIST) { - /* ECMA-357 9.2.1.2. */ - if (js_IdIsIndex(id, &index)) { - /* Step 1 sets i to the property index. */ - i = index; - - /* 2(a-b). */ - if (xml->xml_target) { - ok = ResolveValue(cx, xml->xml_target, &rxml); - if (!ok) - goto out; - if (!rxml) - goto out; - JS_ASSERT(rxml->object); - } else { - rxml = NULL; - } - - /* 2(c). */ - if (index >= xml->xml_kids.length) { - /* 2(c)(i). */ - if (rxml) { - if (rxml->xml_class == JSXML_CLASS_LIST) { - if (rxml->xml_kids.length != 1) - goto out; - rxml = XMLARRAY_MEMBER(&rxml->xml_kids, 0, JSXML); - if (!rxml) - goto out; - ok = js_GetXMLObject(cx, rxml) != NULL; - if (!ok) - goto out; - } - - /* - * Erratum: ECMA-357 9.2.1.2 step 2(c)(ii) sets - * _y.[[Parent]] = r_ where _r_ is the result of - * [[ResolveValue]] called on _x.[[TargetObject]] in - * 2(a)(i). This can result in text parenting text: - * - * var MYXML = new XML(); - * MYXML.appendChild(new XML("Giants")); - * - * (testcase from Werner Sharp ). - * - * To match insertChildAfter, insertChildBefore, - * prependChild, and setChildren, we should silently - * do nothing in this case. - */ - if (!JSXML_HAS_KIDS(rxml)) - goto out; - } - - /* 2(c)(ii) is distributed below as several js_NewXML calls. */ - targetprop = xml->xml_targetprop; - if (!targetprop || IS_STAR(targetprop->localName)) { - /* 2(c)(iv)(1-2), out of order w.r.t. 2(c)(iii). */ - kid = js_NewXML(cx, JSXML_CLASS_TEXT); - if (!kid) - goto bad; - } else { - nameobj = js_GetXMLQNameObject(cx, targetprop); - if (!nameobj) - goto bad; - if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) { - /* - * 2(c)(iii)(1-3). - * Note that rxml can't be null here, because target - * and targetprop are non-null. - */ - ok = GetProperty(cx, rxml->object, id, &attrval); - if (!ok) - goto out; - attrobj = JSVAL_TO_OBJECT(attrval); - attr = (JSXML *) JS_GetPrivate(cx, attrobj); - if (JSXML_LENGTH(attr) != 0) - goto out; - - kid = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); - } else { - /* 2(c)(v). */ - kid = js_NewXML(cx, JSXML_CLASS_ELEMENT); - } - if (!kid) - goto bad; - - /* An important bit of 2(c)(ii). */ - kid->name = targetprop; - } - - /* Final important bit of 2(c)(ii). */ - kid->parent = rxml; - - /* 2(c)(vi-vii). */ - i = xml->xml_kids.length; - if (kid->xml_class != JSXML_CLASS_ATTRIBUTE) { - /* - * 2(c)(vii)(1) tests whether _y.[[Parent]]_ is not null. - * y.[[Parent]] is here called kid->parent, which we know - * from 2(c)(ii) is _r_, here called rxml. So let's just - * test that! Erratum, the spec should be simpler here. - */ - if (rxml) { - JS_ASSERT(JSXML_HAS_KIDS(rxml)); - n = rxml->xml_kids.length; - j = n - 1; - if (n != 0 && i != 0) { - for (n = j, j = 0; j < n; j++) { - if (rxml->xml_kids.vector[j] == - xml->xml_kids.vector[i-1]) { - break; - } - } - } - - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - goto bad; - ok = Insert(cx, rxml, j + 1, OBJECT_TO_JSVAL(kidobj)); - if (!ok) - goto out; - } - - /* - * 2(c)(vii)(2-3). - * Erratum: [[PropertyName]] in 2(c)(vii)(3) must be a - * typo for [[TargetProperty]]. - */ - if (vxml) { - kid->name = (vxml->xml_class == JSXML_CLASS_LIST) - ? vxml->xml_targetprop - : vxml->name; - } - } - - /* 2(c)(viii). */ - ok = Append(cx, xml, kid); - if (!ok) - goto out; - } - - /* 2(d). */ - if (!vxml || - vxml->xml_class == JSXML_CLASS_TEXT || - vxml->xml_class == JSXML_CLASS_ATTRIBUTE) { - ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); - if (!ok) - goto out; - roots[VAL_ROOT] = *vp; - } - - /* 2(e). */ - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (!kid) - goto out; - parent = kid->parent; - if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) { - nameobj = js_GetAttributeNameObject(cx, kid->name); - if (!nameobj) - goto bad; - id = OBJECT_TO_JSVAL(nameobj); - - if (parent) { - /* 2(e)(i). */ - parentobj = parent->object; - ok = PutProperty(cx, parentobj, id, vp); - if (!ok) - goto out; - - /* 2(e)(ii). */ - ok = GetProperty(cx, parentobj, id, vp); - if (!ok) - goto out; - attr = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(*vp)); - - /* 2(e)(iii). */ - xml->xml_kids.vector[i] = attr->xml_kids.vector[0]; - } - } - - /* 2(f). */ - else if (vxml && vxml->xml_class == JSXML_CLASS_LIST) { - /* 2(f)(i) Create a shallow copy _c_ of _V_. */ - copyobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!copyobj) - goto bad; - copy = (JSXML *) JS_GetPrivate(cx, copyobj); - n = vxml->xml_kids.length; - ok = XMLArraySetCapacity(cx, ©->xml_kids, n); - if (!ok) - goto out; - for (k = 0; k < n; k++) { - kid2 = XMLARRAY_MEMBER(&vxml->xml_kids, k, JSXML); - XMLARRAY_SET_MEMBER(©->xml_kids, k, kid2); - } - - JS_ASSERT(parent != xml); - if (parent) { - q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL); - JS_ASSERT(q != XML_NOT_FOUND); - - ok = IndexToIdVal(cx, q, &id); - if (!ok) - goto out; - ok = Replace(cx, parent, id, OBJECT_TO_JSVAL(copyobj)); - if (!ok) - goto out; - -#ifdef DEBUG - /* Erratum: this loop in the spec is useless. */ - for (j = 0, n = copy->xml_kids.length; j < n; j++) { - kid2 = XMLARRAY_MEMBER(&parent->xml_kids, q + j, JSXML); - JS_ASSERT(XMLARRAY_MEMBER(©->xml_kids, j, JSXML) - == kid2); - } -#endif - } - - /* - * 2(f)(iv-vi). - * Erratum: notice the unhandled zero-length V basis case and - * the off-by-one errors for the n != 0 cases in the spec. - */ - if (n == 0) { - XMLArrayDelete(cx, &xml->xml_kids, i, JS_TRUE); - } else { - ok = XMLArrayInsert(cx, &xml->xml_kids, i + 1, n - 1); - if (!ok) - goto out; - - for (j = 0; j < n; j++) - xml->xml_kids.vector[i + j] = copy->xml_kids.vector[j]; - } - } - - /* 2(g). */ - else if (vxml || JSXML_HAS_VALUE(kid)) { - if (parent) { - q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL); - JS_ASSERT(q != XML_NOT_FOUND); - - ok = IndexToIdVal(cx, q, &id); - if (!ok) - goto out; - ok = Replace(cx, parent, id, *vp); - if (!ok) - goto out; - - vxml = XMLARRAY_MEMBER(&parent->xml_kids, q, JSXML); - if (!vxml) - goto out; - roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vxml->object); - } - - /* - * 2(g)(iii). - * Erratum: _V_ may not be of type XML, but all index-named - * properties _x[i]_ in an XMLList _x_ must be of type XML, - * according to 9.2.1.1 Overview and other places in the spec. - * - * Thanks to 2(d), we know _V_ (*vp here) is either a string - * or an XML/XMLList object. If *vp is a string, call ToXML - * on it to satisfy the constraint. - */ - if (!vxml) { - JS_ASSERT(JSVAL_IS_STRING(*vp)); - vobj = ToXML(cx, *vp); - if (!vobj) - goto bad; - roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vobj); - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - } - XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml); - } - - /* 2(h). */ - else { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - goto bad; - id = ATOM_KEY(cx->runtime->atomState.starAtom); - ok = PutProperty(cx, kidobj, id, vp); - if (!ok) - goto out; - } - } else { - /* - * 3. - * Erratum: if x.[[Length]] > 1 or [[ResolveValue]] returns null - * or an r with r.[[Length]] != 1, throw TypeError. - */ - n = JSXML_LENGTH(xml); - if (n > 1) - goto type_error; - if (n == 0) { - ok = ResolveValue(cx, xml, &rxml); - if (!ok) - goto out; - if (!rxml || JSXML_LENGTH(rxml) != 1) - goto type_error; - ok = Append(cx, xml, rxml); - if (!ok) - goto out; - } - JS_ASSERT(JSXML_LENGTH(xml) == 1); - kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (!kid) - goto out; - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - goto bad; - ok = PutProperty(cx, kidobj, id, vp); - if (!ok) - goto out; - } - } else { - /* - * ECMA-357 9.1.1.2. - * Erratum: move steps 3 and 4 to before 1 and 2, to avoid wasted - * effort in ToString or [[DeepCopy]]. - */ - if (js_IdIsIndex(id, &index)) { - /* See NOTE in spec: this variation is reserved for future use. */ - ReportBadXMLName(cx, id); - goto bad; - } - - nameqn = ToXMLName(cx, id, &funid); - if (!nameqn) - goto bad; - if (funid) { - ok = js_SetProperty(cx, obj, funid, vp); - goto out; - } - nameobj = nameqn->object; - - if (JSXML_HAS_VALUE(xml)) - goto out; - - if (!vxml || - vxml->xml_class == JSXML_CLASS_TEXT || - vxml->xml_class == JSXML_CLASS_ATTRIBUTE) { - ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); - if (!ok) - goto out; - } else { - rxml = DeepCopyInLRS(cx, vxml, 0); - if (!rxml || !js_GetXMLObject(cx, rxml)) - goto bad; - vxml = rxml; - *vp = OBJECT_TO_JSVAL(vxml->object); - } - roots[VAL_ROOT] = *vp; - - /* - * 6. - * Erratum: why is this done here, so early? use is way later.... - */ - ok = js_GetDefaultXMLNamespace(cx, &nsval); - if (!ok) - goto out; - - if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) { - /* 7(a). */ - if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj))) - goto out; - - /* 7(b-c). */ - if (vxml && vxml->xml_class == JSXML_CLASS_LIST) { - n = vxml->xml_kids.length; - if (n == 0) { - *vp = STRING_TO_JSVAL(cx->runtime->emptyString); - } else { - left = KidToString(cx, vxml, 0); - if (!left) - goto bad; - - space = ATOM_TO_STRING(cx->runtime->atomState.spaceAtom); - for (i = 1; i < n; i++) { - left = js_ConcatStrings(cx, left, space); - if (!left) - goto bad; - right = KidToString(cx, vxml, i); - if (!right) - goto bad; - left = js_ConcatStrings(cx, left, right); - if (!left) - goto bad; - } - - roots[VAL_ROOT] = *vp = STRING_TO_JSVAL(left); - } - } else { - ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); - if (!ok) - goto out; - roots[VAL_ROOT] = *vp; - } - - /* 7(d-e). */ - match = NULL; - for (i = 0, n = xml->xml_attrs.length; i < n; i++) { - attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); - if (!attr) - continue; - attrqn = attr->name; - if (!js_CompareStrings(attrqn->localName, nameqn->localName) && - (!nameqn->uri || - !js_CompareStrings(attrqn->uri, nameqn->uri))) { - if (!match) { - match = attr; - } else { - nameobj = js_GetAttributeNameObject(cx, attrqn); - if (!nameobj) - goto bad; - - id = OBJECT_TO_JSVAL(nameobj); - ok = DeleteProperty(cx, obj, id, &junk); - if (!ok) - goto out; - --i; - } - } - } - - /* 7(f). */ - attr = match; - if (!attr) { - /* 7(f)(i-ii). */ - if (!nameqn->uri) { - left = right = cx->runtime->emptyString; - } else { - left = nameqn->uri; - right = nameqn->prefix; - } - nameqn = js_NewXMLQName(cx, left, right, nameqn->localName); - if (!nameqn) - goto bad; - - /* 7(f)(iii). */ - attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); - if (!attr) - goto bad; - attr->parent = xml; - attr->name = nameqn; - - /* 7(f)(iv). */ - ok = XMLARRAY_ADD_MEMBER(cx, &xml->xml_attrs, n, attr); - if (!ok) - goto out; - - /* 7(f)(v-vi). */ - ns = GetNamespace(cx, nameqn, NULL); - if (!ns) - goto bad; - ok = AddInScopeNamespace(cx, xml, ns); - if (!ok) - goto out; - } - - /* 7(g). */ - attr->xml_value = JSVAL_TO_STRING(*vp); - goto out; - } - - /* 8-9. */ - if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj)) && - !IS_STAR(nameqn->localName)) { - goto out; - } - - /* 10-11. */ - id = JSVAL_VOID; - primitiveAssign = !vxml && !IS_STAR(nameqn->localName); - - /* 12. */ - k = n = xml->xml_kids.length; - kid2 = NULL; - while (k != 0) { - --k; - kid = XMLARRAY_MEMBER(&xml->xml_kids, k, JSXML); - if (kid && MatchElemName(nameqn, kid)) { - if (!JSVAL_IS_VOID(id)) { - ok = DeleteByIndex(cx, xml, id, &junk); - if (!ok) - goto out; - } - ok = IndexToIdVal(cx, k, &id); - if (!ok) - goto out; - kid2 = kid; - } - } - - /* - * Erratum: ECMA-357 specified child insertion inconsistently: - * insertChildBefore and insertChildAfter insert an arbitrary XML - * instance, and therefore can create cycles, but appendChild as - * specified by the "Overview" of 13.4.4.3 calls [[DeepCopy]] on - * its argument. But the "Semantics" in 13.4.4.3 do not include - * any [[DeepCopy]] call. - * - * Fixing this (https://bugzilla.mozilla.org/show_bug.cgi?id=312692) - * required adding cycle detection, and allowing duplicate kids to - * be created (see comment 6 in the bug). Allowing duplicate kid - * references means the loop above will delete all but the lowest - * indexed reference, and each [[DeleteByIndex]] nulls the kid's - * parent. Thus the need to restore parent here. This is covered - * by https://bugzilla.mozilla.org/show_bug.cgi?id=327564. - */ - if (kid2) { - JS_ASSERT(kid2->parent == xml || !kid2->parent); - if (!kid2->parent) - kid2->parent = xml; - } - - /* 13. */ - if (JSVAL_IS_VOID(id)) { - /* 13(a). */ - ok = IndexToIdVal(cx, n, &id); - if (!ok) - goto out; - - /* 13(b). */ - if (primitiveAssign) { - if (!nameqn->uri) { - ns = (JSXMLNamespace *) - JS_GetPrivate(cx, JSVAL_TO_OBJECT(nsval)); - left = ns->uri; - right = ns->prefix; - } else { - left = nameqn->uri; - right = nameqn->prefix; - } - nameqn = js_NewXMLQName(cx, left, right, nameqn->localName); - if (!nameqn) - goto bad; - - /* 13(b)(iii). */ - vobj = js_NewXMLObject(cx, JSXML_CLASS_ELEMENT); - if (!vobj) - goto bad; - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - vxml->parent = xml; - vxml->name = nameqn; - - /* 13(b)(iv-vi). */ - ns = GetNamespace(cx, nameqn, NULL); - if (!ns) - goto bad; - ok = Replace(cx, xml, id, OBJECT_TO_JSVAL(vobj)); - if (!ok) - goto out; - ok = AddInScopeNamespace(cx, vxml, ns); - if (!ok) - goto out; - } - } - - /* 14. */ - if (primitiveAssign) { - JSXMLArrayCursor cursor; - - js_IdIsIndex(id, &index); - XMLArrayCursorInit(&cursor, &xml->xml_kids); - cursor.index = index; - kid = (JSXML *) XMLArrayCursorItem(&cursor); - if (JSXML_HAS_KIDS(kid)) { - XMLArrayFinish(cx, &kid->xml_kids); - ok = XMLArrayInit(cx, &kid->xml_kids, 1); - } - - /* 14(b-c). */ - /* XXXbe Erratum? redundant w.r.t. 7(b-c) else clause above */ - if (ok) { - ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); - if (ok && !IS_EMPTY(JSVAL_TO_STRING(*vp))) { - roots[VAL_ROOT] = *vp; - if ((JSXML *) XMLArrayCursorItem(&cursor) == kid) - ok = Replace(cx, kid, JSVAL_ZERO, *vp); - } - } - XMLArrayCursorFinish(&cursor); - } else { - /* 15(a). */ - ok = Replace(cx, xml, id, *vp); - } - } - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - JS_LeaveLocalRootScope(cx); - return ok; - -type_error: - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_XMLLIST_PUT, - js_ValueToPrintableString(cx, id)); -bad: - ok = JS_FALSE; - goto out; -} - -/* ECMA-357 9.1.1.10 XML [[ResolveValue]], 9.2.1.10 XMLList [[ResolveValue]]. */ -static JSBool -ResolveValue(JSContext *cx, JSXML *list, JSXML **result) -{ - JSXML *target, *base; - JSXMLQName *targetprop; - JSObject *targetpropobj; - jsval id, tv; - - /* Our caller must be protecting newborn objects. */ - JS_ASSERT(cx->localRootStack); - - if (list->xml_class != JSXML_CLASS_LIST || list->xml_kids.length != 0) { - if (!js_GetXMLObject(cx, list)) - return JS_FALSE; - *result = list; - return JS_TRUE; - } - - target = list->xml_target; - targetprop = list->xml_targetprop; - if (!target || !targetprop || IS_STAR(targetprop->localName)) { - *result = NULL; - return JS_TRUE; - } - - targetpropobj = js_GetXMLQNameObject(cx, targetprop); - if (!targetpropobj) - return JS_FALSE; - if (OBJ_GET_CLASS(cx, targetpropobj) == &js_AttributeNameClass) { - *result = NULL; - return JS_TRUE; - } - - if (!ResolveValue(cx, target, &base)) - return JS_FALSE; - if (!base) { - *result = NULL; - return JS_TRUE; - } - if (!js_GetXMLObject(cx, base)) - return JS_FALSE; - - id = OBJECT_TO_JSVAL(targetpropobj); - if (!GetProperty(cx, base->object, id, &tv)) - return JS_FALSE; - target = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(tv)); - - if (JSXML_LENGTH(target) == 0) { - if (base->xml_class == JSXML_CLASS_LIST && JSXML_LENGTH(base) > 1) { - *result = NULL; - return JS_TRUE; - } - tv = STRING_TO_JSVAL(cx->runtime->emptyString); - if (!PutProperty(cx, base->object, id, &tv)) - return JS_FALSE; - if (!GetProperty(cx, base->object, id, &tv)) - return JS_FALSE; - target = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(tv)); - } - - *result = target; - return JS_TRUE; -} - -/* - * HasProperty must be able to return a found JSProperty and the object in - * which it was found, if id is of the form function::name. For other ids, - * if they index or name an XML child, we return FOUND_XML_PROPERTY in *propp - * and null in *objp. - * - * DROP_PROPERTY helps HasProperty callers drop function properties without - * trying to drop the magic FOUND_XML_PROPERTY cookie. - */ -#define FOUND_XML_PROPERTY ((JSProperty *) 1) -#define DROP_PROPERTY(cx,pobj,prop) (((prop) != FOUND_XML_PROPERTY) \ - ? OBJ_DROP_PROPERTY(cx, pobj, prop) \ - : (void) 0) - -/* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ -static JSBool -HasProperty(JSContext *cx, JSObject *obj, jsval id, JSObject **objp, - JSProperty **propp) -{ - JSXML *xml, *kid; - JSXMLArrayCursor cursor; - JSObject *kidobj; - JSXMLQName *qn; - jsid funid; - JSXMLArray *array; - JSXMLNameMatcher matcher; - uint32 i, n; - - *objp = NULL; - *propp = NULL; - - xml = (JSXML *) JS_GetPrivate(cx, obj); - if (xml->xml_class == JSXML_CLASS_LIST) { - n = JSXML_LENGTH(xml); - if (js_IdIsIndex(id, &i)) { - if (i < n) - *propp = FOUND_XML_PROPERTY; - return JS_TRUE; - } - - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (kid->xml_class == JSXML_CLASS_ELEMENT) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj || !HasProperty(cx, kidobj, id, objp, propp)) - break; - if (*propp) - break; - } - } - XMLArrayCursorFinish(&cursor); - if (kid) - return *propp != NULL; - } else { - if (xml->xml_class == JSXML_CLASS_ELEMENT && js_IdIsIndex(id, &i)) { - if (i == 0) - *propp = FOUND_XML_PROPERTY; - return JS_TRUE; - } - - qn = ToXMLName(cx, id, &funid); - if (!qn) - return JS_FALSE; - if (funid) - return js_LookupProperty(cx, obj, funid, objp, propp); - - if (xml->xml_class != JSXML_CLASS_ELEMENT) - return JS_TRUE; - - if (OBJ_GET_CLASS(cx, qn->object) == &js_AttributeNameClass) { - array = &xml->xml_attrs; - matcher = MatchAttrName; - } else { - array = &xml->xml_kids; - matcher = MatchElemName; - } - for (i = 0, n = array->length; i < n; i++) { - kid = XMLARRAY_MEMBER(array, i, JSXML); - if (kid && matcher(qn, kid)) { - *propp = FOUND_XML_PROPERTY; - return JS_TRUE; - } - } - } - - return JS_TRUE; -} - -static void -xml_finalize(JSContext *cx, JSObject *obj) -{ - JSXML *xml; - - xml = (JSXML *) JS_GetPrivate(cx, obj); - if (!xml) - return; - if (xml->object == obj) - xml->object = NULL; - UNMETER(xml_stats.livexmlobj); -} - -static void -xml_mark_vector(JSContext *cx, JSXML **vec, uint32 len, void *arg) -{ - uint32 i; - JSXML *elt; - - for (i = 0; i < len; i++) { - elt = vec[i]; - { -#ifdef GC_MARK_DEBUG - char buf[120]; - - if (elt->xml_class == JSXML_CLASS_LIST) { - strcpy(buf, js_XMLList_str); - } else if (JSXML_HAS_NAME(elt)) { - JSXMLQName *qn = elt->name; - - JS_snprintf(buf, sizeof buf, "%s::%s", - qn->uri ? JS_GetStringBytes(qn->uri) : "*", - JS_GetStringBytes(qn->localName)); - } else { - JSString *str = elt->xml_value; - size_t srclen = JSSTRING_LENGTH(str); - size_t dstlen = sizeof buf; - - if (srclen >= sizeof buf / 6) - srclen = sizeof buf / 6 - 1; - js_DeflateStringToBuffer(cx, JSSTRING_CHARS(str), srclen, - buf, &dstlen); - } -#else - const char *buf = NULL; -#endif - JS_MarkGCThing(cx, elt, buf, arg); - } - } -} - -/* - * js_XMLObjectOps.newObjectMap == js_NewObjectMap, so XML objects appear to - * be native. Therefore, xml_lookupProperty must return a valid JSProperty - * pointer parameter via *propp to signify "property found". Since the only - * call to xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from - * js_FindXMLProperty (in this file) and js_FindProperty (in jsobj.c, called - * from jsinterp.c), the only time we add a JSScopeProperty here is when an - * unqualified name or XML name is being accessed. - * - * This scope property both speeds up subsequent js_Find*Property calls, and - * keeps the JSOP_NAME code in js_Interpret happy by giving it an sprop with - * (getter, setter) == (GetProperty, PutProperty). We can't use that getter - * and setter as js_XMLClass's getProperty and setProperty, because doing so - * would break the XML methods, which are function-valued properties of the - * XML.prototype object. - * - * NB: xml_deleteProperty must take care to remove any property added here. - */ -static JSBool -xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, - JSProperty **propp) -{ - JSScopeProperty *sprop; - - if (!HasProperty(cx, obj, ID_TO_VALUE(id), objp, propp)) - return JS_FALSE; - - if (*propp == FOUND_XML_PROPERTY) { - sprop = js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, - SPROP_INVALID_SLOT, JSPROP_ENUMERATE, - 0, 0); - if (!sprop) - return JS_FALSE; - - JS_LOCK_OBJ(cx, obj); - *objp = obj; - *propp = (JSProperty *) sprop; - } - return JS_TRUE; -} - -static JSBool -xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs, - JSProperty **propp) -{ - if (JSVAL_IS_FUNCTION(cx, value) || getter || setter || - (attrs & JSPROP_ENUMERATE) == 0 || - (attrs & (JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED))) { - return js_DefineProperty(cx, obj, id, value, getter, setter, attrs, - propp); - } - - if (!PutProperty(cx, obj, ID_TO_VALUE(id), &value)) - return JS_FALSE; - if (propp) - *propp = NULL; - return JS_TRUE; -} - -static JSBool -xml_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) -{ - if (id == JS_DEFAULT_XML_NAMESPACE_ID) { - *vp = JSVAL_VOID; - return JS_TRUE; - } - - return GetProperty(cx, obj, ID_TO_VALUE(id), vp); -} - -static JSBool -xml_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) -{ - return PutProperty(cx, obj, ID_TO_VALUE(id), vp); -} - -static JSBool -FoundProperty(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, - JSBool *foundp) -{ - JSObject *pobj; - - if (prop) { - *foundp = JS_TRUE; - } else { - if (!HasProperty(cx, obj, ID_TO_VALUE(id), &pobj, &prop)) - return JS_FALSE; - if (prop) - DROP_PROPERTY(cx, pobj, prop); - *foundp = (prop != NULL); - } - return JS_TRUE; -} - -static JSBool -xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, - uintN *attrsp) -{ - JSBool found; - - if (!FoundProperty(cx, obj, id, prop, &found)) - return JS_FALSE; - *attrsp = found ? JSPROP_ENUMERATE : 0; - return JS_TRUE; -} - -static JSBool -xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, - uintN *attrsp) -{ - JSBool found; - - if (!FoundProperty(cx, obj, id, prop, &found)) - return JS_FALSE; - if (found) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_CANT_SET_XML_ATTRS); - } - return !found; -} - -static JSBool -xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) -{ - /* - * If this object has its own (mutable) scope, and if id isn't an index, - * then we may have added a property to the scope in xml_lookupProperty - * for it to return to mean "found" and to provide a handle for access - * operations to call the property's getter or setter. The property also - * helps speed up unqualified accesses via the property cache, avoiding - * what amount to two HasProperty searches. - * - * But now it's time to remove any such property, to purge the property - * cache and remove the scope entry. - */ - if (OBJ_SCOPE(obj)->object == obj && !JSID_IS_INT(id)) { - if (!js_DeleteProperty(cx, obj, id, rval)) - return JS_FALSE; - } - - return DeleteProperty(cx, obj, ID_TO_VALUE(id), rval); -} - -static JSBool -xml_defaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) -{ - JSXML *xml; - - if (hint == JSTYPE_OBJECT) { - /* Called from for..in code in js_Interpret: return an XMLList. */ - xml = (JSXML *) JS_GetPrivate(cx, obj); - if (xml->xml_class != JSXML_CLASS_LIST) { - obj = ToXMLList(cx, OBJECT_TO_JSVAL(obj)); - if (!obj) - return JS_FALSE; - } - *vp = OBJECT_TO_JSVAL(obj); - return JS_TRUE; - } - - return JS_CallFunctionName(cx, obj, js_toString_str, 0, NULL, vp); -} - -static JSBool -xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp) -{ - JSXML *xml; - uint32 length, index; - JSXMLArrayCursor *cursor; - - xml = (JSXML *) JS_GetPrivate(cx, obj); - length = JSXML_LENGTH(xml); - - switch (enum_op) { - case JSENUMERATE_INIT: - if (length == 0) { - cursor = NULL; - } else { - cursor = (JSXMLArrayCursor *) JS_malloc(cx, sizeof *cursor); - if (!cursor) - return JS_FALSE; - XMLArrayCursorInit(cursor, &xml->xml_kids); - } - *statep = PRIVATE_TO_JSVAL(cursor); - if (idp) - *idp = INT_TO_JSID(length); - break; - - case JSENUMERATE_NEXT: - cursor = JSVAL_TO_PRIVATE(*statep); - if (cursor && cursor->array && (index = cursor->index) < length) { - *idp = INT_TO_JSID(index); - cursor->index = index + 1; - break; - } - /* FALL THROUGH */ - - case JSENUMERATE_DESTROY: - cursor = JSVAL_TO_PRIVATE(*statep); - if (cursor) { - XMLArrayCursorFinish(cursor); - JS_free(cx, cursor); - } - *statep = JSVAL_NULL; - break; - } - return JS_TRUE; -} - -static JSBool -xml_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) -{ - return JS_TRUE; -} - -static uint32 -xml_mark(JSContext *cx, JSObject *obj, void *arg) -{ - JSXML *xml; - - xml = (JSXML *) JS_GetPrivate(cx, obj); - JS_MarkGCThing(cx, xml, js_private_str, arg); - return js_Mark(cx, obj, arg); -} - -static void -xml_clear(JSContext *cx, JSObject *obj) -{ -} - -static JSBool -HasSimpleContent(JSXML *xml) -{ - JSXML *kid; - JSBool simple; - uint32 i, n; - -again: - switch (xml->xml_class) { - case JSXML_CLASS_COMMENT: - case JSXML_CLASS_PROCESSING_INSTRUCTION: - return JS_FALSE; - case JSXML_CLASS_LIST: - if (xml->xml_kids.length == 0) - return JS_TRUE; - if (xml->xml_kids.length == 1) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (kid) { - xml = kid; - goto again; - } - } - /* FALL THROUGH */ - default: - simple = JS_TRUE; - for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - simple = JS_FALSE; - break; - } - } - return simple; - } -} - -/* - * 11.2.2.1 Step 3(d) onward. - */ -static JSObject * -xml_getMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) -{ - JSXML *xml; - JSTempValueRooter tvr; - jsval roots[2]; - enum { - FUN_ROOT = 0, - OBJ_ROOT = 1 - }; - - JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL)); - xml = (JSXML *) JS_GetPrivate(cx, obj); - memset(roots, 0, sizeof(roots)); - JS_PUSH_TEMP_ROOT(cx, sizeof roots / sizeof *roots, roots, &tvr); - - /* From this point the control must flow through out: or bad: */ - retry: - if (!GetFunction(cx, obj, xml, id, &roots[FUN_ROOT])) - goto bad; - if (JSVAL_IS_VOID(roots[FUN_ROOT]) && OBJECT_IS_XML(cx, obj)) { - if (xml->xml_class == JSXML_CLASS_LIST) { - if (xml->xml_kids.length == 1) { - xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (xml) { - obj = js_GetXMLObject(cx, xml); - if (!obj) - goto bad; - roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); - goto retry; - } - } - } else if (HasSimpleContent(xml)) { - JSString *str; - - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - goto bad; - if (!js_ValueToObject(cx, STRING_TO_JSVAL(str), &obj)) - goto bad; - roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); - if (!js_GetProperty(cx, obj, id, &roots[FUN_ROOT])) - goto bad; - } - } - out: - *vp = roots[FUN_ROOT]; - if (obj) { - /* - * If we just POP tvr, then it is possible that nothing roots obj, see - * bug 353165. To allow our callers to assume at least weakly rooting - * of the result, we root obj via newborn array. Similarly we root the - * value of roots[FUNCTION] since getMethod callers have a bad habit - * of passing a pointer to unrooted local value as vp. - */ - cx->newborn[GCX_OBJECT] = (JSGCThing *)obj; - cx->lastInternalResult = roots[FUN_ROOT]; - } - JS_POP_TEMP_ROOT(cx, &tvr); - return obj; - bad: - obj = NULL; - goto out; -} - -static JSBool -xml_setMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) -{ - return js_SetProperty(cx, obj, id, vp); -} - -static JSBool -xml_enumerateValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp, jsval *vp) -{ - JSXML *xml, *kid; - uint32 length, index; - JSXMLArrayCursor *cursor; - JSObject *kidobj; - - xml = (JSXML *) JS_GetPrivate(cx, obj); - length = JSXML_LENGTH(xml); - JS_ASSERT(INT_FITS_IN_JSVAL(length)); - - switch (enum_op) { - case JSENUMERATE_INIT: - if (length == 0) { - cursor = NULL; - } else { - cursor = (JSXMLArrayCursor *) JS_malloc(cx, sizeof *cursor); - if (!cursor) - return JS_FALSE; - XMLArrayCursorInit(cursor, &xml->xml_kids); - } - *statep = PRIVATE_TO_JSVAL(cursor); - if (idp) - *idp = INT_TO_JSID(length); - if (vp) - *vp = JSVAL_VOID; - break; - - case JSENUMERATE_NEXT: - cursor = JSVAL_TO_PRIVATE(*statep); - if (cursor && cursor->array && (index = cursor->index) < length) { - while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) { - if (++index == length) - goto destroy; - } - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - return JS_FALSE; - JS_ASSERT(INT_FITS_IN_JSVAL(index)); - *idp = INT_TO_JSID(index); - *vp = OBJECT_TO_JSVAL(kidobj); - cursor->index = index + 1; - break; - } - /* FALL THROUGH */ - - case JSENUMERATE_DESTROY: - cursor = JSVAL_TO_PRIVATE(*statep); - if (cursor) { - destroy: - XMLArrayCursorFinish(cursor); - JS_free(cx, cursor); - } - *statep = JSVAL_NULL; - break; - } - return JS_TRUE; -} - -static JSBool -xml_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) -{ - JSXML *xml, *vxml; - JSObject *vobj; - JSBool ok; - JSString *str, *vstr; - jsdouble d, d2; - - xml = (JSXML *) JS_GetPrivate(cx, obj); - vxml = NULL; - if (!JSVAL_IS_PRIMITIVE(v)) { - vobj = JSVAL_TO_OBJECT(v); - if (OBJECT_IS_XML(cx, vobj)) - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - } - - if (xml->xml_class == JSXML_CLASS_LIST) { - ok = Equals(cx, xml, v, bp); - } else if (vxml) { - if (vxml->xml_class == JSXML_CLASS_LIST) { - ok = Equals(cx, vxml, OBJECT_TO_JSVAL(obj), bp); - } else { - if (((xml->xml_class == JSXML_CLASS_TEXT || - xml->xml_class == JSXML_CLASS_ATTRIBUTE) && - HasSimpleContent(vxml)) || - ((vxml->xml_class == JSXML_CLASS_TEXT || - vxml->xml_class == JSXML_CLASS_ATTRIBUTE) && - HasSimpleContent(xml))) { - ok = JS_EnterLocalRootScope(cx); - if (ok) { - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - vstr = js_ValueToString(cx, v); - ok = str && vstr; - if (ok) - *bp = !js_CompareStrings(str, vstr); - JS_LeaveLocalRootScope(cx); - } - } else { - ok = XMLEquals(cx, xml, vxml, bp); - } - } - } else { - ok = JS_EnterLocalRootScope(cx); - if (ok) { - if (HasSimpleContent(xml)) { - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - vstr = js_ValueToString(cx, v); - ok = str && vstr; - if (ok) - *bp = !js_CompareStrings(str, vstr); - } else if (JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v)) { - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) { - ok = JS_FALSE; - } else if (JSVAL_IS_STRING(v)) { - *bp = !js_CompareStrings(str, JSVAL_TO_STRING(v)); - } else { - ok = js_ValueToNumber(cx, STRING_TO_JSVAL(str), &d); - if (ok) { - d2 = JSVAL_IS_INT(v) ? JSVAL_TO_INT(v) - : *JSVAL_TO_DOUBLE(v); - *bp = JSDOUBLE_COMPARE(d, ==, d2, JS_FALSE); - } - } - } else { - *bp = JS_FALSE; - } - JS_LeaveLocalRootScope(cx); - } - } - return ok; -} - -static JSBool -xml_concatenate(JSContext *cx, JSObject *obj, jsval v, jsval *vp) -{ - JSBool ok; - JSObject *listobj, *robj; - JSXML *list, *lxml, *rxml; - - ok = JS_EnterLocalRootScope(cx); - if (!ok) - return JS_FALSE; - - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) { - ok = JS_FALSE; - goto out; - } - - list = (JSXML *) JS_GetPrivate(cx, listobj); - lxml = (JSXML *) JS_GetPrivate(cx, obj); - ok = Append(cx, list, lxml); - if (!ok) - goto out; - - if (VALUE_IS_XML(cx, v)) { - rxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); - } else { - robj = ToXML(cx, v); - if (!robj) { - ok = JS_FALSE; - goto out; - } - rxml = (JSXML *) JS_GetPrivate(cx, robj); - } - ok = Append(cx, list, rxml); - if (!ok) - goto out; - - *vp = OBJECT_TO_JSVAL(listobj); -out: - JS_LeaveLocalRootScope(cx); - return ok; -} - -/* Use js_NewObjectMap so XML objects satisfy OBJ_IS_NATIVE tests. */ -JS_FRIEND_DATA(JSXMLObjectOps) js_XMLObjectOps = { - { js_NewObjectMap, js_DestroyObjectMap, - xml_lookupProperty, xml_defineProperty, - xml_getProperty, xml_setProperty, - xml_getAttributes, xml_setAttributes, - xml_deleteProperty, xml_defaultValue, - xml_enumerate, js_CheckAccess, - NULL, NULL, - NULL, NULL, - NULL, xml_hasInstance, - js_SetProtoOrParent, js_SetProtoOrParent, - xml_mark, xml_clear, - NULL, NULL }, - xml_getMethod, xml_setMethod, - xml_enumerateValues, xml_equality, - xml_concatenate -}; - -static JSObjectOps * -xml_getObjectOps(JSContext *cx, JSClass *clasp) -{ - return &js_XMLObjectOps.base; -} - -JS_FRIEND_DATA(JSClass) js_XMLClass = { - js_XML_str, JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xml_finalize, - xml_getObjectOps, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; - -static JSObject * -CallConstructorFunction(JSContext *cx, JSObject *obj, JSClass *clasp, - uintN argc, jsval *argv) -{ - JSObject *tmp; - jsval rval; - - while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL) - obj = tmp; - if (!JS_CallFunctionName(cx, obj, clasp->name, argc, argv, &rval)) - return NULL; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(rval)); - return JSVAL_TO_OBJECT(rval); -} - -#define XML_METHOD_PROLOG \ - JS_BEGIN_MACRO \ - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, argv); \ - if (!xml) \ - return JS_FALSE; \ - JS_END_MACRO - -static JSBool -xml_addNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - JSObject *nsobj; - JSXMLNamespace *ns; - - XML_METHOD_PROLOG; - if (xml->xml_class != JSXML_CLASS_ELEMENT) - return JS_TRUE; - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - - nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, argv); - if (!nsobj) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nsobj); - - ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); - if (!AddInScopeNamespace(cx, xml, ns)) - return JS_FALSE; - ns->declared = JS_TRUE; - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -static JSBool -xml_appendChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *vxml; - jsval name, v; - JSObject *vobj; - - XML_METHOD_PROLOG; - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - - if (!js_GetAnyName(cx, &name)) - return JS_FALSE; - - if (!GetProperty(cx, obj, name, &v)) - return JS_FALSE; - - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); - vobj = JSVAL_TO_OBJECT(v); - JS_ASSERT(OBJECT_IS_XML(cx, vobj)); - vxml = (JSXML *) JS_GetPrivate(cx, vobj); - JS_ASSERT(vxml->xml_class == JSXML_CLASS_LIST); - - if (!IndexToIdVal(cx, vxml->xml_kids.length, &name)) - return JS_FALSE; - if (!PutProperty(cx, JSVAL_TO_OBJECT(v), name, &argv[0])) - return JS_FALSE; - - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_attribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXMLQName *qn; - - qn = ToAttributeName(cx, argv[0]); - if (!qn) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(qn->object); /* local root */ - return GetProperty(cx, obj, argv[0], rval); -} - -/* XML and XMLList */ -static JSBool -xml_attributes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsval name; - JSXMLQName *qn; - JSTempValueRooter tvr; - JSBool ok; - - name = ATOM_KEY(cx->runtime->atomState.starAtom); - qn = ToAttributeName(cx, name); - if (!qn) - return JS_FALSE; - name = OBJECT_TO_JSVAL(qn->object); - JS_PUSH_SINGLE_TEMP_ROOT(cx, name, &tvr); - ok = GetProperty(cx, obj, name, rval); - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; -} - -/* XML and XMLList */ -static JSBool -xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name, - jsval *rval) -{ - uint32 index; - JSXML *kid; - JSObject *kidobj; - - /* ECMA-357 13.4.4.6 */ - JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); - - if (js_IdIsIndex(name, &index)) { - if (index >= JSXML_LENGTH(xml)) { - *rval = JSVAL_VOID; - } else { - kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); - if (!kid) { - *rval = JSVAL_VOID; - } else { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(kidobj); - } - } - return JS_TRUE; - } - - return GetProperty(cx, obj, name, rval); -} - -static JSBool -xml_child(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml, *list, *kid, *vxml; - JSXMLArrayCursor cursor; - jsval name, v; - JSObject *listobj, *kidobj; - - XML_METHOD_PROLOG; - name = argv[0]; - if (xml->xml_class == JSXML_CLASS_LIST) { - /* ECMA-357 13.5.4.4 */ - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return JS_FALSE; - - *rval = OBJECT_TO_JSVAL(listobj); - list = (JSXML *) JS_GetPrivate(cx, listobj); - list->xml_target = xml; - - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - break; - if (!xml_child_helper(cx, kidobj, kid, name, &v)) - break; - if (JSVAL_IS_VOID(v)) { - /* The property didn't exist in this kid. */ - continue; - } - - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); - vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); - if ((!JSXML_HAS_KIDS(vxml) || vxml->xml_kids.length != 0) && - !Append(cx, list, vxml)) { - break; - } - } - XMLArrayCursorFinish(&cursor); - return !kid; - } - - return xml_child_helper(cx, obj, xml, name, rval); -} - -static JSBool -xml_childIndex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *parent; - uint32 i, n; - - XML_METHOD_PROLOG; - parent = xml->parent; - if (!parent || xml->xml_class == JSXML_CLASS_ATTRIBUTE) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); - return JS_TRUE; - } - for (i = 0, n = JSXML_LENGTH(parent); i < n; i++) { - if (XMLARRAY_MEMBER(&parent->xml_kids, i, JSXML) == xml) - break; - } - JS_ASSERT(i < n); - return js_NewNumberValue(cx, i, rval); -} - -/* XML and XMLList */ -static JSBool -xml_children(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsval name; - - name = ATOM_KEY(cx->runtime->atomState.starAtom); - return GetProperty(cx, obj, name, rval); -} - -/* XML and XMLList */ -static JSBool -xml_comments(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *list, *kid, *vxml; - JSObject *listobj, *kidobj; - JSBool ok; - uint32 i, n; - jsval v; - - XML_METHOD_PROLOG; - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return JS_FALSE; - - *rval = OBJECT_TO_JSVAL(listobj); - list = (JSXML *) JS_GetPrivate(cx, listobj); - list->xml_target = xml; - - ok = JS_TRUE; - - if (xml->xml_class == JSXML_CLASS_LIST) { - /* 13.5.4.6 Step 2. */ - for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - ok = JS_EnterLocalRootScope(cx); - if (!ok) - break; - kidobj = js_GetXMLObject(cx, kid); - ok = kidobj - ? xml_comments(cx, kidobj, argc, argv, &v) - : JS_FALSE; - JS_LeaveLocalRootScope(cx); - if (!ok) - break; - vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); - if (JSXML_LENGTH(vxml) != 0) { - ok = Append(cx, list, vxml); - if (!ok) - break; - } - } - } - } else { - /* 13.4.4.9 Step 2. */ - for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_COMMENT) { - ok = Append(cx, list, kid); - if (!ok) - break; - } - } - } - - return ok; -} - -/* XML and XMLList */ -static JSBool -xml_contains(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *kid; - jsval value; - JSBool eq; - JSXMLArrayCursor cursor; - JSObject *kidobj; - - XML_METHOD_PROLOG; - value = argv[0]; - if (xml->xml_class == JSXML_CLASS_LIST) { - eq = JS_FALSE; - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj || !xml_equality(cx, kidobj, value, &eq)) - break; - if (eq) - break; - } - XMLArrayCursorFinish(&cursor); - if (kid) - return JS_FALSE; - } else { - if (!xml_equality(cx, obj, value, &eq)) - return JS_FALSE; - } - *rval = BOOLEAN_TO_JSVAL(eq); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_copy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml, *copy; - - XML_METHOD_PROLOG; - copy = DeepCopy(cx, xml, NULL, 0); - if (!copy) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(copy->object); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_descendants(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *list; - jsval name; - - XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0]; - list = Descendants(cx, xml, name); - if (!list) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(list->object); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_elements(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *list, *kid, *vxml; - jsval name, v; - JSXMLQName *nameqn; - jsid funid; - JSObject *listobj, *kidobj; - JSBool ok; - JSXMLArrayCursor cursor; - uint32 i, n; - - XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0]; - nameqn = ToXMLName(cx, name, &funid); - if (!nameqn) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameqn->object); - - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(listobj); - if (funid) - return JS_TRUE; - - list = (JSXML *) JS_GetPrivate(cx, listobj); - list->xml_target = xml; - list->xml_targetprop = nameqn; - ok = JS_TRUE; - - if (xml->xml_class == JSXML_CLASS_LIST) { - /* 13.5.4.6 */ - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (kid->xml_class == JSXML_CLASS_ELEMENT) { - ok = JS_EnterLocalRootScope(cx); - if (!ok) - break; - kidobj = js_GetXMLObject(cx, kid); - ok = kidobj - ? xml_elements(cx, kidobj, argc, argv, &v) - : JS_FALSE; - JS_LeaveLocalRootScope(cx); - if (!ok) - break; - vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); - if (JSXML_LENGTH(vxml) != 0) { - ok = Append(cx, list, vxml); - if (!ok) - break; - } - } - } - XMLArrayCursorFinish(&cursor); - } else { - for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT && - MatchElemName(nameqn, kid)) { - ok = Append(cx, list, kid); - if (!ok) - break; - } - } - } - - return ok; -} - -/* XML and XMLList */ -static JSBool -xml_hasOwnProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsval name; - JSObject *pobj; - JSProperty *prop; - - if (!JS_InstanceOf(cx, obj, &js_XMLClass, argv)) - return JS_FALSE; - - name = argv[0]; - if (!HasProperty(cx, obj, name, &pobj, &prop)) - return JS_FALSE; - if (!prop) { - return js_HasOwnPropertyHelper(cx, obj, js_LookupProperty, argc, argv, - rval); - } - DROP_PROPERTY(cx, pobj, prop); - *rval = JSVAL_TRUE; - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_hasComplexContent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *kid; - JSObject *kidobj; - uint32 i, n; - - XML_METHOD_PROLOG; -again: - switch (xml->xml_class) { - case JSXML_CLASS_ATTRIBUTE: - case JSXML_CLASS_COMMENT: - case JSXML_CLASS_PROCESSING_INSTRUCTION: - case JSXML_CLASS_TEXT: - *rval = JSVAL_FALSE; - break; - case JSXML_CLASS_LIST: - if (xml->xml_kids.length == 0) { - *rval = JSVAL_TRUE; - } else if (xml->xml_kids.length == 1) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (kid) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - return JS_FALSE; - obj = kidobj; - xml = (JSXML *) JS_GetPrivate(cx, obj); - goto again; - } - } - /* FALL THROUGH */ - default: - *rval = JSVAL_FALSE; - for (i = 0, n = xml->xml_kids.length; i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - *rval = JSVAL_TRUE; - break; - } - } - break; - } - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_hasSimpleContent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - - XML_METHOD_PROLOG; - *rval = BOOLEAN_TO_JSVAL(HasSimpleContent(xml)); - return JS_TRUE; -} - -typedef struct JSTempRootedNSArray { - JSTempValueRooter tvr; - JSXMLArray array; - jsval value; /* extra root for temporaries */ -} JSTempRootedNSArray; - -JS_STATIC_DLL_CALLBACK(void) -mark_temp_ns_array(JSContext *cx, JSTempValueRooter *tvr) -{ - JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr; - - namespace_mark_vector(cx, - (JSXMLNamespace **)tmp->array.vector, - tmp->array.length, NULL); - XMLArrayCursorMark(cx, tmp->array.cursors); - if (JSVAL_IS_GCTHING(tmp->value)) - GC_MARK(cx, JSVAL_TO_GCTHING(tmp->value), "temp_ns_array_value", NULL); -} - -static void -InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) -{ - XMLArrayInit(cx, &tmp->array, 0); - tmp->value = JSVAL_NULL; - JS_PUSH_TEMP_ROOT_MARKER(cx, mark_temp_ns_array, &tmp->tvr); -} - -static void -FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) -{ - JS_ASSERT(tmp->tvr.u.marker == mark_temp_ns_array); - JS_POP_TEMP_ROOT(cx, &tmp->tvr); - XMLArrayFinish(cx, &tmp->array); -} - -/* - * Populate a new JS array with elements of JSTempRootedNSArray.array and - * place the result into rval. rval must point to a rooted location. - */ -static JSBool -TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval) -{ - JSObject *arrayobj; - uint32 i, n; - JSXMLNamespace *ns; - JSObject *nsobj; - - arrayobj = js_NewArrayObject(cx, 0, NULL); - if (!arrayobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(arrayobj); - for (i = 0, n = tmp->array.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&tmp->array, i, JSXMLNamespace); - if (!ns) - continue; - nsobj = js_GetXMLNamespaceObject(cx, ns); - if (!nsobj) - return JS_FALSE; - tmp->value = OBJECT_TO_JSVAL(nsobj); - if (!OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(i), &tmp->value)) - return JS_FALSE; - } - return JS_TRUE; -} - -static JSBool -FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) -{ - uint32 length, i, j, n; - JSXMLNamespace *ns, *ns2; - - length = nsarray->length; - do { - if (xml->xml_class != JSXML_CLASS_ELEMENT) - continue; - for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace); - if (!ns) - continue; - - for (j = 0; j < length; j++) { - ns2 = XMLARRAY_MEMBER(nsarray, j, JSXMLNamespace); - if (ns2 && - ((ns2->prefix && ns->prefix) - ? !js_CompareStrings(ns2->prefix, ns->prefix) - : !js_CompareStrings(ns2->uri, ns->uri))) { - break; - } - } - - if (j == length) { - if (!XMLARRAY_APPEND(cx, nsarray, ns)) - return JS_FALSE; - ++length; - } - } - } while ((xml = xml->parent) != NULL); - JS_ASSERT(length == nsarray->length); - - return JS_TRUE; -} - -static JSBool -xml_inScopeNamespaces(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - JSTempRootedNSArray namespaces; - JSBool ok; - - XML_METHOD_PROLOG; - - InitTempNSArray(cx, &namespaces); - ok = FindInScopeNamespaces(cx, xml, &namespaces.array) && - TempNSArrayToJSArray(cx, &namespaces, rval); - FinishTempNSArray(cx, &namespaces); - return ok; -} - -static JSBool -xml_insertChildAfter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *kid; - jsval arg; - uint32 i; - - XML_METHOD_PROLOG; - if (!JSXML_HAS_KIDS(xml)) - return JS_TRUE; - - arg = argv[0]; - if (JSVAL_IS_NULL(arg)) { - kid = NULL; - i = 0; - } else { - if (!VALUE_IS_XML(cx, arg)) - return JS_TRUE; - kid = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(arg)); - i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL); - if (i == XML_NOT_FOUND) - return JS_TRUE; - ++i; - } - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - if (!Insert(cx, xml, i, argv[1])) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -static JSBool -xml_insertChildBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *kid; - jsval arg; - uint32 i; - - XML_METHOD_PROLOG; - if (!JSXML_HAS_KIDS(xml)) - return JS_TRUE; - - arg = argv[0]; - if (JSVAL_IS_NULL(arg)) { - kid = NULL; - i = xml->xml_kids.length; - } else { - if (!VALUE_IS_XML(cx, arg)) - return JS_TRUE; - kid = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(arg)); - i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL); - if (i == XML_NOT_FOUND) - return JS_TRUE; - } - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - if (!Insert(cx, xml, i, argv[1])) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_length(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml; - - XML_METHOD_PROLOG; - if (xml->xml_class != JSXML_CLASS_LIST) { - *rval = JSVAL_ONE; - } else { - if (!js_NewNumberValue(cx, xml->xml_kids.length, rval)) - return JS_FALSE; - } - return JS_TRUE; -} - -static JSBool -xml_localName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - - XML_METHOD_PROLOG; - *rval = xml->name ? STRING_TO_JSVAL(xml->name->localName) : JSVAL_NULL; - return JS_TRUE; -} - -static JSBool -xml_name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml; - JSObject *nameobj; - - XML_METHOD_PROLOG; - if (!xml->name) { - *rval = JSVAL_NULL; - } else { - nameobj = js_GetXMLQNameObject(cx, xml->name); - if (!nameobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(nameobj); - } - return JS_TRUE; -} - -static JSBool -xml_namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - JSString *prefix; - JSTempRootedNSArray inScopeNSes; - JSBool ok; - jsuint i, length; - JSXMLNamespace *ns; - JSObject *nsobj; - - XML_METHOD_PROLOG; - if (argc == 0 && - (xml->xml_class == JSXML_CLASS_TEXT || - xml->xml_class == JSXML_CLASS_COMMENT || - xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION)) { - *rval = JSVAL_NULL; - return JS_TRUE; - } - - if (argc == 0) { - prefix = NULL; - } else { - prefix = js_ValueToString(cx, argv[0]); - if (!prefix) - return JS_FALSE; - argv[0] = STRING_TO_JSVAL(prefix); /* local root */ - } - - /* After this point the control must flow through label out. */ - InitTempNSArray(cx, &inScopeNSes); - ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array); - if (!ok) - goto out; - - if (!prefix) { - ns = GetNamespace(cx, xml->name, &inScopeNSes.array); - if (!ns) { - ok = JS_FALSE; - goto out; - } - } else { - ns = NULL; - for (i = 0, length = inScopeNSes.array.length; i < length; i++) { - ns = XMLARRAY_MEMBER(&inScopeNSes.array, i, JSXMLNamespace); - if (ns && ns->prefix && !js_CompareStrings(ns->prefix, prefix)) - break; - ns = NULL; - } - } - - if (!ns) { - *rval = JSVAL_VOID; - } else { - nsobj = js_GetXMLNamespaceObject(cx, ns); - if (!nsobj) { - ok = JS_FALSE; - goto out; - } - *rval = OBJECT_TO_JSVAL(nsobj); - } - - out: - FinishTempNSArray(cx, &inScopeNSes); - return JS_TRUE; -} - -static JSBool -xml_namespaceDeclarations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *yml; - JSBool ok; - JSTempRootedNSArray ancestors, declared; - uint32 i, n; - JSXMLNamespace *ns; - - XML_METHOD_PROLOG; - if (JSXML_HAS_VALUE(xml) || xml->xml_class == JSXML_CLASS_LIST) - return JS_TRUE; - - /* From here, control flow must goto out to finish these arrays. */ - ok = JS_TRUE; - InitTempNSArray(cx, &ancestors); - InitTempNSArray(cx, &declared); - yml = xml; - - while ((yml = yml->parent) != NULL) { - JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT); - for (i = 0, n = yml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSXMLNamespace); - if (ns && - !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - ok = XMLARRAY_APPEND(cx, &ancestors.array, ns); - if (!ok) - goto out; - } - } - } - - for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace); - if (!ns) - continue; - if (!ns->declared) - continue; - if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - ok = XMLARRAY_APPEND(cx, &declared.array, ns); - if (!ok) - goto out; - } - } - - ok = TempNSArrayToJSArray(cx, &declared, rval); - -out: - /* Finishing must be in reverse order of initialization to follow LIFO. */ - FinishTempNSArray(cx, &declared); - FinishTempNSArray(cx, &ancestors); - return ok; -} - -static const char js_attribute_str[] = "attribute"; -static const char js_text_str[] = "text"; - -/* Exported to jsgc.c #ifdef GC_MARK_DEBUG. */ -const char *js_xml_class_str[] = { - "list", - "element", - js_attribute_str, - "processing-instruction", - js_text_str, - "comment" -}; - -static JSBool -xml_nodeKind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - JSString *str; - - XML_METHOD_PROLOG; - str = JS_InternString(cx, js_xml_class_str[xml->xml_class]); - if (!str) - return JS_FALSE; - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -static JSBool -NormalizingDelete(JSContext *cx, JSObject *obj, JSXML *xml, jsval id) -{ - jsval junk; - - if (xml->xml_class == JSXML_CLASS_LIST) - return DeleteProperty(cx, obj, id, &junk); - return DeleteByIndex(cx, xml, id, &junk); -} - -/* - * Erratum? the testcase js/tests/e4x/XML/13.4.4.26.js wants all-whitespace - * text between tags to be removed by normalize. - */ -static JSBool -IsXMLSpace(JSString *str) -{ - const jschar *cp, *end; - - cp = JSSTRING_CHARS(str); - end = cp + JSSTRING_LENGTH(str); - while (cp < end) { - if (!JS_ISXMLSPACE(*cp)) - return JS_FALSE; - ++cp; - } - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_normalize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *kid, *kid2; - uint32 i, n; - JSObject *kidobj; - JSString *str; - jsval junk; - - XML_METHOD_PROLOG; - *rval = OBJECT_TO_JSVAL(obj); - if (!JSXML_HAS_KIDS(xml)) - return JS_TRUE; - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - - for (i = 0, n = xml->xml_kids.length; i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (!kid) - continue; - if (kid->xml_class == JSXML_CLASS_ELEMENT) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj || !xml_normalize(cx, kidobj, argc, argv, &junk)) - return JS_FALSE; - } else if (kid->xml_class == JSXML_CLASS_TEXT) { - while (i + 1 < n && - (kid2 = XMLARRAY_MEMBER(&xml->xml_kids, i + 1, JSXML)) && - kid2->xml_class == JSXML_CLASS_TEXT) { - str = js_ConcatStrings(cx, kid->xml_value, kid2->xml_value); - if (!str) - return JS_FALSE; - if (!NormalizingDelete(cx, obj, xml, INT_TO_JSVAL(i + 1))) - return JS_FALSE; - n = xml->xml_kids.length; - kid->xml_value = str; - } - if (IS_EMPTY(kid->xml_value) || IsXMLSpace(kid->xml_value)) { - if (!NormalizingDelete(cx, obj, xml, INT_TO_JSVAL(i))) - return JS_FALSE; - n = xml->xml_kids.length; - --i; - } - } - } - - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_parent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml, *parent, *kid; - uint32 i, n; - JSObject *parentobj; - - XML_METHOD_PROLOG; - parent = xml->parent; - if (xml->xml_class == JSXML_CLASS_LIST) { - *rval = JSVAL_VOID; - n = xml->xml_kids.length; - if (n == 0) - return JS_TRUE; - - kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); - if (!kid) - return JS_TRUE; - parent = kid->parent; - for (i = 1; i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->parent != parent) - return JS_TRUE; - } - } - - if (!parent) { - *rval = JSVAL_NULL; - return JS_TRUE; - } - - parentobj = js_GetXMLObject(cx, parent); - if (!parentobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(parentobj); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_processingInstructions(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - JSXML *xml, *list, *kid, *vxml; - jsval name, v; - JSXMLQName *nameqn; - jsid funid; - JSObject *listobj, *kidobj; - JSBool ok; - JSXMLArrayCursor cursor; - uint32 i, n; - - XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0]; - nameqn = ToXMLName(cx, name, &funid); - if (!nameqn) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameqn->object); - - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(listobj); - if (funid) - return JS_TRUE; - - list = (JSXML *) JS_GetPrivate(cx, listobj); - list->xml_target = xml; - list->xml_targetprop = nameqn; - ok = JS_TRUE; - - if (xml->xml_class == JSXML_CLASS_LIST) { - /* 13.5.4.17 Step 4 (misnumbered 9 -- Erratum?). */ - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (kid->xml_class == JSXML_CLASS_ELEMENT) { - ok = JS_EnterLocalRootScope(cx); - if (!ok) - break; - kidobj = js_GetXMLObject(cx, kid); - ok = kidobj - ? xml_processingInstructions(cx, kidobj, argc, argv, &v) - : JS_FALSE; - JS_LeaveLocalRootScope(cx); - if (!ok) - break; - vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); - if (JSXML_LENGTH(vxml) != 0) { - ok = Append(cx, list, vxml); - if (!ok) - break; - } - } - } - XMLArrayCursorFinish(&cursor); - } else { - /* 13.4.4.28 Step 4. */ - for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION && - (IS_STAR(nameqn->localName) || - !js_CompareStrings(nameqn->localName, kid->name->localName))) { - ok = Append(cx, list, kid); - if (!ok) - break; - } - } - } - - return ok; -} - -static JSBool -xml_prependChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - - XML_METHOD_PROLOG; - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - return Insert(cx, xml, 0, argv[0]); -} - -/* XML and XMLList */ -static JSBool -xml_propertyIsEnumerable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - jsval name; - uint32 index; - - XML_METHOD_PROLOG; - name = argv[0]; - *rval = JSVAL_FALSE; - if (js_IdIsIndex(name, &index)) { - if (xml->xml_class == JSXML_CLASS_LIST) { - /* 13.5.4.18. */ - *rval = BOOLEAN_TO_JSVAL(index < xml->xml_kids.length); - } else { - /* 13.4.4.30. */ - *rval = BOOLEAN_TO_JSVAL(index == 0); - } - } - return JS_TRUE; -} - -static JSBool -namespace_full_match(const void *a, const void *b) -{ - const JSXMLNamespace *nsa = (const JSXMLNamespace *) a; - const JSXMLNamespace *nsb = (const JSXMLNamespace *) b; - - if (nsa->prefix && nsb->prefix && - js_CompareStrings(nsa->prefix, nsb->prefix)) { - return JS_FALSE; - } - return !js_CompareStrings(nsa->uri, nsb->uri); -} - -static JSBool -xml_removeNamespace_helper(JSContext *cx, JSXML *xml, JSXMLNamespace *ns) -{ - JSXMLNamespace *thisns, *attrns; - uint32 i, n; - JSXML *attr, *kid; - - thisns = GetNamespace(cx, xml->name, &xml->xml_namespaces); - JS_ASSERT(thisns); - if (thisns == ns) - return JS_TRUE; - - for (i = 0, n = xml->xml_attrs.length; i < n; i++) { - attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); - if (!attr) - continue; - attrns = GetNamespace(cx, attr->name, &xml->xml_namespaces); - JS_ASSERT(attrns); - if (attrns == ns) - return JS_TRUE; - } - - i = XMLARRAY_FIND_MEMBER(&xml->xml_namespaces, ns, namespace_full_match); - if (i != XML_NOT_FOUND) - XMLArrayDelete(cx, &xml->xml_namespaces, i, JS_TRUE); - - for (i = 0, n = xml->xml_kids.length; i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - if (!xml_removeNamespace_helper(cx, kid, ns)) - return JS_FALSE; - } - } - return JS_TRUE; -} - -static JSBool -xml_removeNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - JSObject *nsobj; - JSXMLNamespace *ns; - - XML_METHOD_PROLOG; - *rval = OBJECT_TO_JSVAL(obj); - if (xml->xml_class != JSXML_CLASS_ELEMENT) - return JS_TRUE; - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - - nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, argv); - if (!nsobj) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nsobj); - ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); - - /* NOTE: remove ns from each ancestor if not used by that ancestor. */ - return xml_removeNamespace_helper(cx, xml, ns); -} - -static JSBool -xml_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml, *vxml, *kid; - jsval name, value, id, junk; - uint32 index; - JSObject *nameobj; - JSXMLQName *nameqn; - - XML_METHOD_PROLOG; - *rval = OBJECT_TO_JSVAL(obj); - if (xml->xml_class != JSXML_CLASS_ELEMENT) - return JS_TRUE; - - value = argv[1]; - vxml = VALUE_IS_XML(cx, value) - ? (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(value)) - : NULL; - if (!vxml) { - if (!JS_ConvertValue(cx, value, JSTYPE_STRING, &argv[1])) - return JS_FALSE; - value = argv[1]; - } else { - vxml = DeepCopy(cx, vxml, NULL, 0); - if (!vxml) - return JS_FALSE; - value = argv[1] = OBJECT_TO_JSVAL(vxml->object); - } - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - - name = argv[0]; - if (js_IdIsIndex(name, &index)) - return Replace(cx, xml, name, value); - - /* Call function QName per spec, not ToXMLName, to avoid attribute names. */ - nameobj = CallConstructorFunction(cx, obj, &js_QNameClass.base, 1, &name); - if (!nameobj) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameobj); - nameqn = (JSXMLQName *) JS_GetPrivate(cx, nameobj); - - id = JSVAL_VOID; - index = xml->xml_kids.length; - while (index != 0) { - --index; - kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); - if (kid && MatchElemName(nameqn, kid)) { - if (!JSVAL_IS_VOID(id) && !DeleteByIndex(cx, xml, id, &junk)) - return JS_FALSE; - if (!IndexToIdVal(cx, index, &id)) - return JS_FALSE; - } - } - if (JSVAL_IS_VOID(id)) - return JS_TRUE; - return Replace(cx, xml, id, value); -} - -static JSBool -xml_setChildren(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - if (!PutProperty(cx, obj, ATOM_KEY(cx->runtime->atomState.starAtom), - &argv[0])) { - return JS_FALSE; - } - - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -static JSBool -xml_setLocalName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - jsval name; - JSXMLQName *nameqn; - JSString *namestr; - - XML_METHOD_PROLOG; - if (!JSXML_HAS_NAME(xml)) - return JS_TRUE; - - name = argv[0]; - if (!JSVAL_IS_PRIMITIVE(name) && - OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base) { - nameqn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(name)); - namestr = nameqn->localName; - } else { - if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &argv[0])) - return JS_FALSE; - name = argv[0]; - namestr = JSVAL_TO_STRING(name); - } - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - xml->name->localName = namestr; - return JS_TRUE; -} - -static JSBool -xml_setName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml, *nsowner; - jsval name; - JSXMLQName *nameqn; - JSObject *nameobj; - JSXMLArray *nsarray; - uint32 i, n; - JSXMLNamespace *ns; - - XML_METHOD_PROLOG; - if (!JSXML_HAS_NAME(xml)) - return JS_TRUE; - - name = argv[0]; - if (!JSVAL_IS_PRIMITIVE(name) && - OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base && - !(nameqn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(name))) - ->uri) { - name = argv[0] = STRING_TO_JSVAL(nameqn->localName); - } - - nameobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &name); - if (!nameobj) - return JS_FALSE; - nameqn = (JSXMLQName *) JS_GetPrivate(cx, nameobj); - - /* ECMA-357 13.4.4.35 Step 4. */ - if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) - nameqn->uri = cx->runtime->emptyString; - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml) - return JS_FALSE; - xml->name = nameqn; - - /* - * Erratum: nothing in 13.4.4.35 talks about making the name match the - * in-scope namespaces, either by finding an in-scope namespace with a - * matching uri and setting the new name's prefix to that namespace's - * prefix, or by extending the in-scope namespaces for xml (which are in - * xml->parent if xml is an attribute or a PI). - */ - if (xml->xml_class == JSXML_CLASS_ELEMENT) { - nsowner = xml; - } else { - if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT) - return JS_TRUE; - nsowner = xml->parent; - } - - if (nameqn->prefix) { - /* - * The name being set has a prefix, which originally came from some - * namespace object (which may be the null namespace, where both the - * prefix and uri are the empty string). We must go through a full - * GetNamespace in case that namespace is in-scope in nsowner. - * - * If we find such an in-scope namespace, we return true right away, - * in this block. Otherwise, we fall through to the final return of - * AddInScopeNamespace(cx, nsowner, ns). - */ - ns = GetNamespace(cx, nameqn, &nsowner->xml_namespaces); - if (!ns) - return JS_FALSE; - - /* XXXbe have to test membership to see whether GetNamespace added */ - if (XMLARRAY_HAS_MEMBER(&nsowner->xml_namespaces, ns, NULL)) - return JS_TRUE; - } else { - /* - * At this point, we know nameqn->prefix is null, so nameqn->uri can't - * be the empty string (the null namespace always uses the empty string - * for both prefix and uri). - * - * This means we must inline GetNamespace and specialize it to match - * uri only, never prefix. If we find a namespace with nameqn's uri - * already in nsowner->xml_namespaces, then all that we need do is set - * nameqn->prefix to that namespace's prefix. - * - * If no such namespace exists, we can create one without going through - * the constructor, because we know nameqn->uri is non-empty (so prefix - * does not need to be converted from null to empty by QName). - */ - JS_ASSERT(!IS_EMPTY(nameqn->uri)); - - nsarray = &nsowner->xml_namespaces; - for (i = 0, n = nsarray->length; i < n; i++) { - ns = XMLARRAY_MEMBER(nsarray, i, JSXMLNamespace); - if (ns && !js_CompareStrings(ns->uri, nameqn->uri)) { - nameqn->prefix = ns->prefix; - return JS_TRUE; - } - } - - ns = js_NewXMLNamespace(cx, NULL, nameqn->uri, JS_TRUE); - if (!ns) - return JS_FALSE; - } - - return AddInScopeNamespace(cx, nsowner, ns); -} - -static JSBool -xml_setNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml, *nsowner; - JSObject *nsobj, *qnobj; - JSXMLNamespace *ns; - jsval qnargv[2]; - - XML_METHOD_PROLOG; - if (xml->xml_class != JSXML_CLASS_ELEMENT && - xml->xml_class != JSXML_CLASS_ATTRIBUTE) { - return JS_TRUE; - } - - xml = CHECK_COPY_ON_WRITE(cx, xml, obj); - if (!xml || !js_GetXMLQNameObject(cx, xml->name)) - return JS_FALSE; - - nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 1, argv); - if (!nsobj) - return JS_FALSE; - ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); - ns->declared = JS_TRUE; - - qnargv[0] = argv[0] = OBJECT_TO_JSVAL(nsobj); - qnargv[1] = OBJECT_TO_JSVAL(xml->name->object); - qnobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, qnargv); - if (!qnobj) - return JS_FALSE; - - xml->name = (JSXMLQName *) JS_GetPrivate(cx, qnobj); - - /* - * Erratum: the spec fails to update the governing in-scope namespaces. - * See the erratum noted in xml_setName, above. - */ - if (xml->xml_class == JSXML_CLASS_ELEMENT) { - nsowner = xml; - } else { - if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT) - return JS_TRUE; - nsowner = xml->parent; - } - return AddInScopeNamespace(cx, nsowner, ns); -} - -/* XML and XMLList */ -static JSBool -xml_text(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSXML *xml, *list, *kid, *vxml; - JSObject *listobj, *kidobj; - uint32 i, n; - JSBool ok; - jsval v; - - XML_METHOD_PROLOG; - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return JS_FALSE; - - *rval = OBJECT_TO_JSVAL(listobj); - list = (JSXML *) JS_GetPrivate(cx, listobj); - list->xml_target = xml; - - if (xml->xml_class == JSXML_CLASS_LIST) { - ok = JS_TRUE; - for (i = 0, n = xml->xml_kids.length; i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - ok = JS_EnterLocalRootScope(cx); - if (!ok) - break; - kidobj = js_GetXMLObject(cx, kid); - ok = kidobj - ? xml_text(cx, kidobj, argc, argv, &v) - : JS_FALSE; - JS_LeaveLocalRootScope(cx); - if (!ok) - return JS_FALSE; - vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); - if (JSXML_LENGTH(vxml) != 0 && !Append(cx, list, vxml)) - return JS_FALSE; - } - } - } else { - for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { - kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); - if (kid && kid->xml_class == JSXML_CLASS_TEXT) { - if (!Append(cx, list, kid)) - return JS_FALSE; - } - } - } - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_toXMLString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSString *str; - - str = ToXMLString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - return JS_FALSE; - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSString * -xml_toString_helper(JSContext *cx, JSXML *xml) -{ - JSString *str, *kidstr; - JSXML *kid; - JSXMLArrayCursor cursor; - - if (xml->xml_class == JSXML_CLASS_ATTRIBUTE || - xml->xml_class == JSXML_CLASS_TEXT) { - return xml->xml_value; - } - - if (!HasSimpleContent(xml)) - return ToXMLString(cx, OBJECT_TO_JSVAL(xml->object)); - - str = cx->runtime->emptyString; - JS_EnterLocalRootScope(cx); - XMLArrayCursorInit(&cursor, &xml->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - if (kid->xml_class != JSXML_CLASS_COMMENT && - kid->xml_class != JSXML_CLASS_PROCESSING_INSTRUCTION) { - kidstr = xml_toString_helper(cx, kid); - if (!kidstr) { - str = NULL; - break; - } - str = js_ConcatStrings(cx, str, kidstr); - if (!str) - break; - } - } - XMLArrayCursorFinish(&cursor); - JS_LeaveLocalRootScope(cx); - return str; -} - -static JSBool -xml_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSXML *xml; - JSString *str; - - XML_METHOD_PROLOG; - str = xml_toString_helper(cx, xml); - if (!str) - return JS_FALSE; - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -/* XML and XMLList */ -static JSBool -xml_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -static JSFunctionSpec xml_methods[] = { - {"addNamespace", xml_addNamespace, 1,0,XML_MASK}, - {"appendChild", xml_appendChild, 1,0,XML_MASK}, - {js_attribute_str, xml_attribute, 1,0,GENERIC_MASK}, - {"attributes", xml_attributes, 0,0,GENERIC_MASK}, - {"child", xml_child, 1,0,GENERIC_MASK}, - {"childIndex", xml_childIndex, 0,0,XML_MASK}, - {"children", xml_children, 0,0,GENERIC_MASK}, - {"comments", xml_comments, 0,0,GENERIC_MASK}, - {"contains", xml_contains, 1,0,GENERIC_MASK}, - {"copy", xml_copy, 0,0,GENERIC_MASK}, - {"descendants", xml_descendants, 1,0,GENERIC_MASK}, - {"elements", xml_elements, 1,0,GENERIC_MASK}, - {"hasOwnProperty", xml_hasOwnProperty, 1,0,GENERIC_MASK}, - {"hasComplexContent", xml_hasComplexContent, 1,0,GENERIC_MASK}, - {"hasSimpleContent", xml_hasSimpleContent, 1,0,GENERIC_MASK}, - {"inScopeNamespaces", xml_inScopeNamespaces, 0,0,XML_MASK}, - {"insertChildAfter", xml_insertChildAfter, 2,0,XML_MASK}, - {"insertChildBefore", xml_insertChildBefore, 2,0,XML_MASK}, - {js_length_str, xml_length, 0,0,GENERIC_MASK}, - {js_localName_str, xml_localName, 0,0,XML_MASK}, - {js_name_str, xml_name, 0,0,XML_MASK}, - {js_namespace_str, xml_namespace, 1,0,XML_MASK}, - {"namespaceDeclarations", xml_namespaceDeclarations, 0,0,XML_MASK}, - {"nodeKind", xml_nodeKind, 0,0,XML_MASK}, - {"normalize", xml_normalize, 0,0,GENERIC_MASK}, - {js_xml_parent_str, xml_parent, 0,0,GENERIC_MASK}, - {"processingInstructions",xml_processingInstructions,1,0,GENERIC_MASK}, - {"prependChild", xml_prependChild, 1,0,XML_MASK}, - {"propertyIsEnumerable", xml_propertyIsEnumerable, 1,0,GENERIC_MASK}, - {"removeNamespace", xml_removeNamespace, 1,0,XML_MASK}, - {"replace", xml_replace, 2,0,XML_MASK}, - {"setChildren", xml_setChildren, 1,0,XML_MASK}, - {"setLocalName", xml_setLocalName, 1,0,XML_MASK}, - {"setName", xml_setName, 1,0,XML_MASK}, - {"setNamespace", xml_setNamespace, 1,0,XML_MASK}, - {js_text_str, xml_text, 0,0,GENERIC_MASK}, - {js_toString_str, xml_toString, 0,0,GENERIC_MASK}, - {js_toXMLString_str, xml_toXMLString, 0,0,GENERIC_MASK}, - {js_toSource_str, xml_toXMLString, 0,0,GENERIC_MASK}, - {js_valueOf_str, xml_valueOf, 0,0,GENERIC_MASK}, - {0,0,0,0,0} -}; - -static JSBool -CopyXMLSettings(JSContext *cx, JSObject *from, JSObject *to) -{ - int i; - const char *name; - jsval v; - - for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) { - name = xml_static_props[i].name; - if (!JS_GetProperty(cx, from, name, &v)) - return JS_FALSE; - if (JSVAL_IS_BOOLEAN(v) && !JS_SetProperty(cx, to, name, &v)) - return JS_FALSE; - } - - name = xml_static_props[i].name; - if (!JS_GetProperty(cx, from, name, &v)) - return JS_FALSE; - if (JSVAL_IS_NUMBER(v) && !JS_SetProperty(cx, to, name, &v)) - return JS_FALSE; - return JS_TRUE; -} - -static JSBool -SetDefaultXMLSettings(JSContext *cx, JSObject *obj) -{ - int i; - jsval v; - - for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) { - v = JSVAL_TRUE; - if (!JS_SetProperty(cx, obj, xml_static_props[i].name, &v)) - return JS_FALSE; - } - v = INT_TO_JSVAL(2); - return JS_SetProperty(cx, obj, xml_static_props[i].name, &v); -} - -static JSBool -xml_settings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSObject *settings; - - settings = JS_NewObject(cx, NULL, NULL, NULL); - if (!settings) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(settings); - return CopyXMLSettings(cx, obj, settings); -} - -static JSBool -xml_setSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsval v; - JSBool ok; - JSObject *settings; - - v = argv[0]; - if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { - cx->xmlSettingFlags = 0; - ok = SetDefaultXMLSettings(cx, obj); - } else { - if (JSVAL_IS_PRIMITIVE(v)) - return JS_TRUE; - settings = JSVAL_TO_OBJECT(v); - cx->xmlSettingFlags = 0; - ok = CopyXMLSettings(cx, settings, obj); - } - if (ok) - cx->xmlSettingFlags |= XSF_CACHE_VALID; - return ok; -} - -static JSBool -xml_defaultSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *settings; - - settings = JS_NewObject(cx, NULL, NULL, NULL); - if (!settings) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(settings); - return SetDefaultXMLSettings(cx, settings); -} - -static JSFunctionSpec xml_static_methods[] = { - {"settings", xml_settings, 0,0,0}, - {"setSettings", xml_setSettings, 1,0,0}, - {"defaultSettings", xml_defaultSettings, 0,0,0}, - {0,0,0,0,0} -}; - -static JSBool -XML(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval v; - JSXML *xml, *copy; - JSObject *xobj, *vobj; - JSClass *clasp; - - v = argv[0]; - if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) - v = STRING_TO_JSVAL(cx->runtime->emptyString); - - xobj = ToXML(cx, v); - if (!xobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(xobj); - xml = (JSXML *) JS_GetPrivate(cx, xobj); - - if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) { - vobj = JSVAL_TO_OBJECT(v); - clasp = OBJ_GET_CLASS(cx, vobj); - if (clasp == &js_XMLClass || - (clasp->flags & JSCLASS_DOCUMENT_OBSERVER)) { - /* No need to lock obj, it's newly constructed and thread local. */ - copy = DeepCopy(cx, xml, obj, 0); - if (!copy) - return JS_FALSE; - JS_ASSERT(copy->object == obj); - *rval = OBJECT_TO_JSVAL(obj); - return JS_TRUE; - } - } - return JS_TRUE; -} - -static JSBool -XMLList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsval v; - JSObject *vobj, *listobj; - JSXML *xml, *list; - - v = argv[0]; - if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) - v = STRING_TO_JSVAL(cx->runtime->emptyString); - - if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) { - vobj = JSVAL_TO_OBJECT(v); - if (OBJECT_IS_XML(cx, vobj)) { - xml = (JSXML *) JS_GetPrivate(cx, vobj); - if (xml->xml_class == JSXML_CLASS_LIST) { - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(listobj); - - list = (JSXML *) JS_GetPrivate(cx, listobj); - if (!Append(cx, list, xml)) - return JS_FALSE; - return JS_TRUE; - } - } - } - - /* Toggle on XML support since the script has explicitly requested it. */ - listobj = ToXMLList(cx, v); - if (!listobj) - return JS_FALSE; - - *rval = OBJECT_TO_JSVAL(listobj); - return JS_TRUE; -} - -#define JSXML_LIST_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLListVar)) -#define JSXML_ELEMENT_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLVar)) -#define JSXML_LEAF_SIZE (offsetof(JSXML, u) + sizeof(JSString *)) - -static size_t sizeof_JSXML[JSXML_CLASS_LIMIT] = { - JSXML_LIST_SIZE, /* JSXML_CLASS_LIST */ - JSXML_ELEMENT_SIZE, /* JSXML_CLASS_ELEMENT */ - JSXML_LEAF_SIZE, /* JSXML_CLASS_ATTRIBUTE */ - JSXML_LEAF_SIZE, /* JSXML_CLASS_PROCESSING_INSTRUCTION */ - JSXML_LEAF_SIZE, /* JSXML_CLASS_TEXT */ - JSXML_LEAF_SIZE /* JSXML_CLASS_COMMENT */ -}; - -#ifdef DEBUG_notme -JSCList xml_leaks = JS_INIT_STATIC_CLIST(&xml_leaks); -uint32 xml_serial; -#endif - -JSXML * -js_NewXML(JSContext *cx, JSXMLClass xml_class) -{ - JSXML *xml; - - xml = (JSXML *) js_NewGCThing(cx, GCX_XML, sizeof_JSXML[xml_class]); - if (!xml) - return NULL; - - xml->object = NULL; - xml->domnode = NULL; - xml->parent = NULL; - xml->name = NULL; - xml->xml_class = xml_class; - xml->xml_flags = 0; - if (JSXML_CLASS_HAS_VALUE(xml_class)) { - xml->xml_value = cx->runtime->emptyString; - } else { - XMLArrayInit(cx, &xml->xml_kids, 0); - if (xml_class == JSXML_CLASS_LIST) { - xml->xml_target = NULL; - xml->xml_targetprop = NULL; - } else { - XMLArrayInit(cx, &xml->xml_namespaces, 0); - XMLArrayInit(cx, &xml->xml_attrs, 0); - } - } - -#ifdef DEBUG_notme - JS_APPEND_LINK(&xml->links, &xml_leaks); - xml->serial = xml_serial++; -#endif - METER(xml_stats.xml); - METER(xml_stats.livexml); - return xml; -} - -static void -xml_mark_tail(JSContext *cx, JSXML *xml, void *arg) -{ - XMLArrayTrim(&xml->xml_kids); - - if (xml->xml_class == JSXML_CLASS_LIST) { - if (xml->xml_target) - JS_MarkGCThing(cx, xml->xml_target, "target", arg); - if (xml->xml_targetprop) - JS_MarkGCThing(cx, xml->xml_targetprop, "targetprop", arg); - } else { - namespace_mark_vector(cx, - (JSXMLNamespace **) xml->xml_namespaces.vector, - xml->xml_namespaces.length, - arg); - XMLArrayCursorMark(cx, xml->xml_namespaces.cursors); - XMLArrayTrim(&xml->xml_namespaces); - - xml_mark_vector(cx, - (JSXML **) xml->xml_attrs.vector, - xml->xml_attrs.length, - arg); - XMLArrayCursorMark(cx, xml->xml_attrs.cursors); - XMLArrayTrim(&xml->xml_attrs); - } -} - -void -js_MarkXML(JSContext *cx, JSXML *xml, void *arg) -{ - JS_MarkGCThing(cx, xml->object, js_object_str, arg); - JS_MarkGCThing(cx, xml->name, js_name_str, arg); - JS_MarkGCThing(cx, xml->parent, js_xml_parent_str, arg); - - if (JSXML_HAS_VALUE(xml)) { - JS_MarkGCThing(cx, xml->xml_value, "value", arg); - } else { - xml_mark_vector(cx, - (JSXML **) xml->xml_kids.vector, - xml->xml_kids.length, - arg); - XMLArrayCursorMark(cx, xml->xml_kids.cursors); - - xml_mark_tail(cx, xml, arg); - } -} - -void -js_FinalizeXML(JSContext *cx, JSXML *xml) -{ - if (JSXML_HAS_KIDS(xml)) { - XMLArrayFinish(cx, &xml->xml_kids); - if (xml->xml_class == JSXML_CLASS_ELEMENT) { - XMLArrayFinish(cx, &xml->xml_namespaces); - XMLArrayFinish(cx, &xml->xml_attrs); - } - } - -#ifdef DEBUG_notme - JS_REMOVE_LINK(&xml->links); -#endif - - UNMETER(xml_stats.livexml); -} - -JSObject * -js_ParseNodeToXMLObject(JSContext *cx, JSParseNode *pn) -{ - jsval nsval; - JSXMLNamespace *ns; - JSXMLArray nsarray; - JSXML *xml; - - if (!js_GetDefaultXMLNamespace(cx, &nsval)) - return NULL; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval)); - ns = (JSXMLNamespace *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(nsval)); - - if (!XMLArrayInit(cx, &nsarray, 1)) - return NULL; - - XMLARRAY_APPEND(cx, &nsarray, ns); - xml = ParseNodeToXML(cx, pn, &nsarray, XSF_PRECOMPILED_ROOT); - XMLArrayFinish(cx, &nsarray); - if (!xml) - return NULL; - - return xml->object; -} - -JSObject * -js_NewXMLObject(JSContext *cx, JSXMLClass xml_class) -{ - JSXML *xml; - JSObject *obj; - JSTempValueRooter tvr; - - xml = js_NewXML(cx, xml_class); - if (!xml) - return NULL; - JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(xml), &tvr); - obj = js_GetXMLObject(cx, xml); - JS_POP_TEMP_ROOT(cx, &tvr); - return obj; -} - -static JSObject * -NewXMLObject(JSContext *cx, JSXML *xml) -{ - JSObject *obj; - - obj = js_NewObject(cx, &js_XMLClass, NULL, NULL); - if (!obj || !JS_SetPrivate(cx, obj, xml)) { - cx->newborn[GCX_OBJECT] = NULL; - return NULL; - } - METER(xml_stats.xmlobj); - METER(xml_stats.livexmlobj); - return obj; -} - -JSObject * -js_GetXMLObject(JSContext *cx, JSXML *xml) -{ - JSObject *obj; - - obj = xml->object; - if (obj) { - JS_ASSERT(JS_GetPrivate(cx, obj) == xml); - return obj; - } - - /* - * A JSXML cannot be shared among threads unless it has an object. - * A JSXML cannot be given an object unless: - * (a) it has no parent; or - * (b) its parent has no object (therefore is thread-private); or - * (c) its parent's object is locked. - * - * Once given an object, a JSXML is immutable. - */ - JS_ASSERT(!xml->parent || - !xml->parent->object || - JS_IS_OBJ_LOCKED(cx, xml->parent->object)); - - obj = NewXMLObject(cx, xml); - if (!obj) - return NULL; - xml->object = obj; - return obj; -} - -JSObject * -js_InitNamespaceClass(JSContext *cx, JSObject *obj) -{ - return JS_InitClass(cx, obj, NULL, &js_NamespaceClass.base, Namespace, 2, - namespace_props, namespace_methods, NULL, NULL); -} - -JSObject * -js_InitQNameClass(JSContext *cx, JSObject *obj) -{ - return JS_InitClass(cx, obj, NULL, &js_QNameClass.base, QName, 2, - qname_props, qname_methods, NULL, NULL); -} - -JSObject * -js_InitAttributeNameClass(JSContext *cx, JSObject *obj) -{ - return JS_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2, - qname_props, qname_methods, NULL, NULL); -} - -JSObject * -js_InitAnyNameClass(JSContext *cx, JSObject *obj) -{ - jsval v; - - if (!js_GetAnyName(cx, &v)) - return NULL; - return JSVAL_TO_OBJECT(v); -} - -JSObject * -js_InitXMLClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto, *pobj, *ctor; - JSFunctionSpec *fs; - JSFunction *fun; - JSXML *xml; - JSProperty *prop; - JSScopeProperty *sprop; - jsval cval, argv[1], junk; - - /* Define the isXMLName function. */ - if (!JS_DefineFunction(cx, obj, js_isXMLName_str, xml_isXMLName, 1, 0)) - return NULL; - - /* Define the XML class constructor and prototype. */ - proto = JS_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, - NULL, NULL, - xml_static_props, xml_static_methods); - if (!proto) - return NULL; - - /* - * XXX Hack alert: expand JS_DefineFunctions here to copy fs->extra into - * fun->spare, clearing fun->extra. No xml_methods require extra local GC - * roots allocated after actual arguments on the VM stack, but we need a - * way to tell which methods work only on XML objects, which work only on - * XMLList objects, and which work on either. - */ - for (fs = xml_methods; fs->name; fs++) { - fun = JS_DefineFunction(cx, proto, fs->name, fs->call, fs->nargs, - fs->flags); - if (!fun) - return NULL; - fun->extra = 0; - fun->spare = fs->extra; - } - - xml = js_NewXML(cx, JSXML_CLASS_TEXT); - if (!xml || !JS_SetPrivate(cx, proto, xml)) - return NULL; - xml->object = proto; - METER(xml_stats.xmlobj); - METER(xml_stats.livexmlobj); - - /* - * Prepare to set default settings on the XML constructor we just made. - * NB: We can't use JS_GetConstructor, because it calls OBJ_GET_PROPERTY, - * which is xml_getProperty, which creates a new XMLList every time! We - * must instead call js_LookupProperty directly. - */ - if (!js_LookupProperty(cx, proto, - ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), - &pobj, &prop)) { - return NULL; - } - JS_ASSERT(prop); - sprop = (JSScopeProperty *) prop; - JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))); - cval = OBJ_GET_SLOT(cx, pobj, sprop->slot); - OBJ_DROP_PROPERTY(cx, pobj, prop); - JS_ASSERT(JSVAL_IS_FUNCTION(cx, cval)); - - /* Set default settings. */ - ctor = JSVAL_TO_OBJECT(cval); - argv[0] = JSVAL_VOID; - if (!xml_setSettings(cx, ctor, 1, argv, &junk)) - return NULL; - - /* Define the XMLList function and give it the same prototype as XML. */ - fun = JS_DefineFunction(cx, obj, js_XMLList_str, XMLList, 1, 0); - if (!fun) - return NULL; - if (!js_SetClassPrototype(cx, fun->object, proto, - JSPROP_READONLY | JSPROP_PERMANENT)) { - return NULL; - } - return proto; -} - -JSObject * -js_InitXMLClasses(JSContext *cx, JSObject *obj) -{ - if (!js_InitNamespaceClass(cx, obj)) - return NULL; - if (!js_InitQNameClass(cx, obj)) - return NULL; - if (!js_InitAttributeNameClass(cx, obj)) - return NULL; - if (!js_InitAnyNameClass(cx, obj)) - return NULL; - return js_InitXMLClass(cx, obj); -} - -JSBool -js_GetFunctionNamespace(JSContext *cx, jsval *vp) -{ - JSRuntime *rt; - JSObject *obj; - JSAtom *atom; - JSString *prefix, *uri; - - /* An invalid URI, for internal use only, guaranteed not to collide. */ - static const char anti_uri[] = "@mozilla.org/js/function"; - - rt = cx->runtime; - obj = rt->functionNamespaceObject; - if (!obj) { - atom = js_Atomize(cx, js_function_str, 8, 0); - JS_ASSERT(atom); - prefix = ATOM_TO_STRING(atom); - - atom = js_Atomize(cx, anti_uri, sizeof anti_uri - 1, ATOM_PINNED); - if (!atom) - return JS_FALSE; - rt->atomState.lazy.functionNamespaceURIAtom = atom; - - uri = ATOM_TO_STRING(atom); - obj = js_NewXMLNamespaceObject(cx, prefix, uri, JS_FALSE); - if (!obj) - return JS_FALSE; - - /* - * Avoid entraining any in-scope Object.prototype. The loss of - * Namespace.prototype is not detectable, as there is no way to - * refer to this instance in scripts. When used to qualify method - * names, its prefix and uri references are copied to the QName. - */ - OBJ_SET_PROTO(cx, obj, NULL); - OBJ_SET_PARENT(cx, obj, NULL); - rt->functionNamespaceObject = obj; - } - *vp = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -/* - * Note the asymmetry between js_GetDefaultXMLNamespace and js_SetDefaultXML- - * Namespace. Get searches fp->scopeChain for JS_DEFAULT_XML_NAMESPACE_ID, - * while Set sets JS_DEFAULT_XML_NAMESPACE_ID in fp->varobj (unless fp is a - * lightweight function activation). There's no requirement that fp->varobj - * lie directly on fp->scopeChain, although it should be reachable using the - * prototype chain from a scope object (cf. JSOPTION_VAROBJFIX in jsapi.h). - * - * If Get can't find JS_DEFAULT_XML_NAMESPACE_ID along the scope chain, it - * creates a default namespace via 'new Namespace()'. In contrast, Set uses - * its v argument as the uri of a new Namespace, with "" as the prefix. See - * ECMA-357 12.1 and 12.1.1. Note that if Set is called with a Namespace n, - * the default XML namespace will be set to ("", n.uri). So the uri string - * is really the only usefully stored value of the default namespace. - */ -JSBool -js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) -{ - JSStackFrame *fp; - JSObject *nsobj, *obj, *tmp; - jsval v; - - fp = cx->fp; - nsobj = fp->xmlNamespace; - if (nsobj) { - *vp = OBJECT_TO_JSVAL(nsobj); - return JS_TRUE; - } - - obj = NULL; - for (tmp = fp->scopeChain; tmp; tmp = OBJ_GET_PARENT(cx, obj)) { - obj = tmp; - if (!OBJ_GET_PROPERTY(cx, obj, JS_DEFAULT_XML_NAMESPACE_ID, &v)) - return JS_FALSE; - if (!JSVAL_IS_PRIMITIVE(v)) { - fp->xmlNamespace = JSVAL_TO_OBJECT(v); - *vp = v; - return JS_TRUE; - } - } - - nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 0, NULL); - if (!nsobj) - return JS_FALSE; - v = OBJECT_TO_JSVAL(nsobj); - if (obj && - !OBJ_DEFINE_PROPERTY(cx, obj, JS_DEFAULT_XML_NAMESPACE_ID, v, - JS_PropertyStub, JS_PropertyStub, - JSPROP_PERMANENT, NULL)) { - return JS_FALSE; - } - fp->xmlNamespace = nsobj; - *vp = v; - return JS_TRUE; -} - -JSBool -js_SetDefaultXMLNamespace(JSContext *cx, jsval v) -{ - jsval argv[2]; - JSObject *nsobj, *varobj; - JSStackFrame *fp; - - argv[0] = STRING_TO_JSVAL(cx->runtime->emptyString); - argv[1] = v; - nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, - 2, argv); - if (!nsobj) - return JS_FALSE; - v = OBJECT_TO_JSVAL(nsobj); - - fp = cx->fp; - varobj = fp->varobj; - if (varobj) { - if (!OBJ_DEFINE_PROPERTY(cx, varobj, JS_DEFAULT_XML_NAMESPACE_ID, v, - JS_PropertyStub, JS_PropertyStub, - JSPROP_PERMANENT, NULL)) { - return JS_FALSE; - } - } else { - JS_ASSERT(fp->fun && !(fp->fun->flags & JSFUN_HEAVYWEIGHT)); - } - fp->xmlNamespace = JSVAL_TO_OBJECT(v); - return JS_TRUE; -} - -JSBool -js_ToAttributeName(JSContext *cx, jsval *vp) -{ - JSXMLQName *qn; - - qn = ToAttributeName(cx, *vp); - if (!qn) - return JS_FALSE; - *vp = OBJECT_TO_JSVAL(qn->object); - return JS_TRUE; -} - -JSString * -js_EscapeAttributeValue(JSContext *cx, JSString *str) -{ - return EscapeAttributeValue(cx, NULL, str); -} - -JSString * -js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2) -{ - size_t len, len2, newlen; - jschar *chars; - - if (JSSTRING_IS_DEPENDENT(str) || - !(*js_GetGCThingFlags(str) & GCF_MUTABLE)) { - str = js_NewStringCopyN(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str), - 0); - if (!str) - return NULL; - } - - len = str->length; - len2 = JSSTRING_LENGTH(str2); - newlen = (isName) ? len + 1 + len2 : len + 2 + len2 + 1; - chars = (jschar *) JS_realloc(cx, str->chars, (newlen+1) * sizeof(jschar)); - if (!chars) - return NULL; - - /* - * Reallocating str (because we know it has no other references) requires - * purging any deflated string cached for it. - */ - js_PurgeDeflatedStringCache(str); - - str->chars = chars; - str->length = newlen; - chars += len; - if (isName) { - *chars++ = ' '; - js_strncpy(chars, JSSTRING_CHARS(str2), len2); - chars += len2; - } else { - *chars++ = '='; - *chars++ = '"'; - js_strncpy(chars, JSSTRING_CHARS(str2), len2); - chars += len2; - *chars++ = '"'; - } - *chars = 0; - return str; -} - -JSString * -js_EscapeElementValue(JSContext *cx, JSString *str) -{ - return EscapeElementValue(cx, NULL, str); -} - -JSString * -js_ValueToXMLString(JSContext *cx, jsval v) -{ - return ToXMLString(cx, v); -} - -static JSBool -anyname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - *rval = ATOM_KEY(cx->runtime->atomState.starAtom); - return JS_TRUE; -} - -JSBool -js_GetAnyName(JSContext *cx, jsval *vp) -{ - JSRuntime *rt; - JSObject *obj; - JSXMLQName *qn; - - rt = cx->runtime; - obj = rt->anynameObject; - if (!obj) { - qn = js_NewXMLQName(cx, rt->emptyString, rt->emptyString, - ATOM_TO_STRING(rt->atomState.starAtom)); - if (!qn) - return JS_FALSE; - - obj = js_NewObject(cx, &js_AnyNameClass, NULL, NULL); - if (!obj || !JS_SetPrivate(cx, obj, qn)) { - cx->newborn[GCX_OBJECT] = NULL; - return JS_FALSE; - } - qn->object = obj; - METER(xml_stats.qnameobj); - METER(xml_stats.liveqnameobj); - - /* - * Avoid entraining any in-scope Object.prototype. This loses the - * default toString inheritance, but no big deal: we want a better - * custom one for clearer diagnostics. - */ - if (!JS_DefineFunction(cx, obj, js_toString_str, anyname_toString, - 0, 0)) { - return JS_FALSE; - } - OBJ_SET_PROTO(cx, obj, NULL); - JS_ASSERT(!OBJ_GET_PARENT(cx, obj)); - rt->anynameObject = obj; - } - *vp = OBJECT_TO_JSVAL(obj); - return JS_TRUE; -} - -JSBool -js_FindXMLProperty(JSContext *cx, jsval name, JSObject **objp, jsval *namep) -{ - JSXMLQName *qn; - jsid funid, id; - JSObject *obj, *pobj, *lastobj; - JSProperty *prop; - const char *printable; - - qn = ToXMLName(cx, name, &funid); - if (!qn) - return JS_FALSE; - id = OBJECT_TO_JSID(qn->object); - - obj = cx->fp->scopeChain; - do { - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) - return JS_FALSE; - if (prop) { - OBJ_DROP_PROPERTY(cx, pobj, prop); - - /* - * Call OBJ_THIS_OBJECT to skip any With object that wraps an XML - * object to carry scope chain linkage in js_FilterXMLList. - */ - pobj = OBJ_THIS_OBJECT(cx, obj); - if (OBJECT_IS_XML(cx, pobj)) { - *objp = pobj; - *namep = ID_TO_VALUE(id); - return JS_TRUE; - } - } - - lastobj = obj; - } while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL); - - printable = js_ValueToPrintableString(cx, name); - if (printable) { - JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, - js_GetErrorMessage, NULL, - JSMSG_UNDEFINED_XML_NAME, printable); - } - return JS_FALSE; -} - -JSBool -js_GetXMLProperty(JSContext *cx, JSObject *obj, jsval name, jsval *vp) -{ - return GetProperty(cx, obj, name, vp); -} - -JSBool -js_SetXMLProperty(JSContext *cx, JSObject *obj, jsval name, jsval *vp) -{ - return PutProperty(cx, obj, name, vp); -} - -static JSXML * -GetPrivate(JSContext *cx, JSObject *obj, const char *method) -{ - JSXML *xml; - - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); - if (!xml) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_INCOMPATIBLE_METHOD, - js_XML_str, method, OBJ_GET_CLASS(cx, obj)->name); - } - return xml; -} - -JSBool -js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - JSXML *xml, *list; - - xml = GetPrivate(cx, obj, "descendants internal method"); - if (!xml) - return JS_FALSE; - - list = Descendants(cx, xml, id); - if (!list) - return JS_FALSE; - *vp = OBJECT_TO_JSVAL(list->object); - return JS_TRUE; -} - -JSBool -js_DeleteXMLListElements(JSContext *cx, JSObject *listobj) -{ - JSXML *list; - uint32 n; - jsval junk; - - list = (JSXML *) JS_GetPrivate(cx, listobj); - for (n = list->xml_kids.length; n != 0; --n) { - if (!DeleteProperty(cx, listobj, INT_TO_JSID(0), &junk)) - return JS_FALSE; - } - return JS_TRUE; -} - -JSBool -js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, jsval *vp) -{ - JSBool ok, match; - JSStackFrame *fp; - JSObject *scobj, *listobj, *resobj, *withobj, *kidobj; - JSXML *xml, *list, *result, *kid; - JSXMLArrayCursor cursor; - - ok = JS_EnterLocalRootScope(cx); - if (!ok) - return JS_FALSE; - - /* All control flow after this point must exit via label out or bad. */ - fp = cx->fp; - scobj = fp->scopeChain; - withobj = NULL; - xml = GetPrivate(cx, obj, "filtering predicate operator"); - if (!xml) - goto bad; - - if (xml->xml_class == JSXML_CLASS_LIST) { - list = xml; - } else { - listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - goto bad; - list = (JSXML *) JS_GetPrivate(cx, listobj); - ok = Append(cx, list, xml); - if (!ok) - goto out; - } - - resobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!resobj) - goto bad; - result = (JSXML *) JS_GetPrivate(cx, resobj); - - /* Hoist the scope chain update out of the loop over kids. */ - withobj = js_NewWithObject(cx, NULL, scobj, -1); - if (!withobj) - goto bad; - fp->scopeChain = withobj; - - XMLArrayCursorInit(&cursor, &list->xml_kids); - while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) { - kidobj = js_GetXMLObject(cx, kid); - if (!kidobj) - break; - OBJ_SET_PROTO(cx, withobj, kidobj); - ok = js_Interpret(cx, pc, vp) && js_ValueToBoolean(cx, *vp, &match); - if (ok && match) - ok = Append(cx, result, kid); - if (!ok) - break; - } - XMLArrayCursorFinish(&cursor); - if (!ok) - goto out; - if (kid) - goto bad; - - *vp = OBJECT_TO_JSVAL(resobj); - -out: - if (withobj) { - fp->scopeChain = scobj; - JS_SetPrivate(cx, withobj, NULL); - } - JS_LeaveLocalRootScope(cx); - return ok; -bad: - ok = JS_FALSE; - goto out; -} - -JSObject * -js_ValueToXMLObject(JSContext *cx, jsval v) -{ - return ToXML(cx, v); -} - -JSObject * -js_ValueToXMLListObject(JSContext *cx, jsval v) -{ - return ToXMLList(cx, v); -} - -JSObject * -js_CloneXMLObject(JSContext *cx, JSObject *obj) -{ - uintN flags; - JSXML *xml; - - if (!GetXMLSettingFlags(cx, &flags)) - return NULL; - xml = (JSXML *) JS_GetPrivate(cx, obj); - if (flags & (XSF_IGNORE_COMMENTS | - XSF_IGNORE_PROCESSING_INSTRUCTIONS | - XSF_IGNORE_WHITESPACE)) { - xml = DeepCopy(cx, xml, NULL, flags); - if (!xml) - return NULL; - return xml->object; - } - return NewXMLObject(cx, xml); -} - -JSObject * -js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name, - JSString *value) -{ - uintN flags; - JSObject *obj; - JSXML *xml; - JSXMLQName *qn; - - if (!GetXMLSettingFlags(cx, &flags)) - return NULL; - - if ((xml_class == JSXML_CLASS_COMMENT && - (flags & XSF_IGNORE_COMMENTS)) || - (xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION && - (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS))) { - return js_NewXMLObject(cx, JSXML_CLASS_TEXT); - } - - obj = js_NewXMLObject(cx, xml_class); - if (!obj) - return NULL; - xml = (JSXML *) JS_GetPrivate(cx, obj); - if (name) { - qn = js_NewXMLQName(cx, cx->runtime->emptyString, NULL, name); - if (!qn) - return NULL; - xml->name = qn; - } - xml->xml_value = value; - return obj; -} - -JSString * -js_MakeXMLCDATAString(JSContext *cx, JSString *str) -{ - return MakeXMLCDATAString(cx, NULL, str); -} - -JSString * -js_MakeXMLCommentString(JSContext *cx, JSString *str) -{ - return MakeXMLCommentString(cx, NULL, str); -} - -JSString * -js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str) -{ - return MakeXMLPIString(cx, NULL, name, str); -} - -#endif /* JS_HAS_XML_SUPPORT */ diff --git a/src/dom/js/jsxml.h b/src/dom/js/jsxml.h deleted file mode 100644 index 294e66c90..000000000 --- a/src/dom/js/jsxml.h +++ /dev/null @@ -1,329 +0,0 @@ -/* -*- 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 SpiderMonkey E4X code, released August, 2004. - * - * 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 jsxml_h___ -#define jsxml_h___ - -#include "jsstddef.h" -#include "jspubtd.h" - -extern const char js_AnyName_str[]; -extern const char js_AttributeName_str[]; -extern const char js_isXMLName_str[]; -extern const char js_XMLList_str[]; - -extern const char js_amp_entity_str[]; -extern const char js_gt_entity_str[]; -extern const char js_lt_entity_str[]; -extern const char js_quot_entity_str[]; - -struct JSXMLNamespace { - JSObject *object; - JSString *prefix; - JSString *uri; - JSBool declared; /* true if declared in its XML tag */ -}; - -extern JSXMLNamespace * -js_NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri, - JSBool declared); - -extern void -js_MarkXMLNamespace(JSContext *cx, JSXMLNamespace *ns, void *arg); - -extern void -js_FinalizeXMLNamespace(JSContext *cx, JSXMLNamespace *ns); - -extern JSObject * -js_NewXMLNamespaceObject(JSContext *cx, JSString *prefix, JSString *uri, - JSBool declared); - -extern JSObject * -js_GetXMLNamespaceObject(JSContext *cx, JSXMLNamespace *ns); - -struct JSXMLQName { - JSObject *object; - JSString *uri; - JSString *prefix; - JSString *localName; -}; - -extern JSXMLQName * -js_NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, - JSString *localName); - -extern void -js_MarkXMLQName(JSContext *cx, JSXMLQName *qn, void *arg); - -extern void -js_FinalizeXMLQName(JSContext *cx, JSXMLQName *qn); - -extern JSObject * -js_NewXMLQNameObject(JSContext *cx, JSString *uri, JSString *prefix, - JSString *localName); - -extern JSObject * -js_GetXMLQNameObject(JSContext *cx, JSXMLQName *qn); - -extern JSObject * -js_GetAttributeNameObject(JSContext *cx, JSXMLQName *qn); - -extern JSObject * -js_ConstructXMLQNameObject(JSContext *cx, jsval nsval, jsval lnval); - -typedef JSBool -(* JS_DLL_CALLBACK JSIdentityOp)(const void *a, const void *b); - -struct JSXMLArray { - uint32 length; - uint32 capacity; - void **vector; - JSXMLArrayCursor *cursors; -}; - -#define JSXML_PRESET_CAPACITY JS_BIT(31) -#define JSXML_CAPACITY_MASK JS_BITMASK(31) -#define JSXML_CAPACITY(array) ((array)->capacity & JSXML_CAPACITY_MASK) - -struct JSXMLArrayCursor { - JSXMLArray *array; - uint32 index; - JSXMLArrayCursor *next; - JSXMLArrayCursor **prevp; - void *root; -}; - -/* - * NB: don't reorder this enum without changing all array initializers that - * depend on it in jsxml.c. - */ -typedef enum JSXMLClass { - JSXML_CLASS_LIST, - JSXML_CLASS_ELEMENT, - JSXML_CLASS_ATTRIBUTE, - JSXML_CLASS_PROCESSING_INSTRUCTION, - JSXML_CLASS_TEXT, - JSXML_CLASS_COMMENT, - JSXML_CLASS_LIMIT -} JSXMLClass; - -#define JSXML_CLASS_HAS_KIDS(class_) ((class_) < JSXML_CLASS_ATTRIBUTE) -#define JSXML_CLASS_HAS_VALUE(class_) ((class_) >= JSXML_CLASS_ATTRIBUTE) -#define JSXML_CLASS_HAS_NAME(class_) \ - ((uintN)((class_) - JSXML_CLASS_ELEMENT) <= \ - (uintN)(JSXML_CLASS_PROCESSING_INSTRUCTION - JSXML_CLASS_ELEMENT)) - -#ifdef DEBUG_notme -#include "jsclist.h" -#endif - -struct JSXML { -#ifdef DEBUG_notme - JSCList links; - uint32 serial; -#endif - JSObject *object; - void *domnode; /* DOM node if mapped info item */ - JSXML *parent; - JSXMLQName *name; - uint16 xml_class; /* discriminates u, below */ - uint16 xml_flags; /* flags, see below */ - union { - struct JSXMLListVar { - JSXMLArray kids; /* NB: must come first */ - JSXML *target; - JSXMLQName *targetprop; - } list; - struct JSXMLVar { - JSXMLArray kids; /* NB: must come first */ - JSXMLArray namespaces; - JSXMLArray attrs; - } elem; - JSString *value; - } u; - - /* Don't add anything after u -- see js_NewXML for why. */ -}; - -/* union member shorthands */ -#define xml_kids u.list.kids -#define xml_target u.list.target -#define xml_targetprop u.list.targetprop -#define xml_namespaces u.elem.namespaces -#define xml_attrs u.elem.attrs -#define xml_value u.value - -/* xml_flags values */ -#define XMLF_WHITESPACE_TEXT 0x1 - -/* xml_class-testing macros */ -#define JSXML_HAS_KIDS(xml) JSXML_CLASS_HAS_KIDS((xml)->xml_class) -#define JSXML_HAS_VALUE(xml) JSXML_CLASS_HAS_VALUE((xml)->xml_class) -#define JSXML_HAS_NAME(xml) JSXML_CLASS_HAS_NAME((xml)->xml_class) -#define JSXML_LENGTH(xml) (JSXML_CLASS_HAS_KIDS((xml)->xml_class) \ - ? (xml)->xml_kids.length \ - : 0) - -extern JSXML * -js_NewXML(JSContext *cx, JSXMLClass xml_class); - -extern void -js_MarkXML(JSContext *cx, JSXML *xml, void *arg); - -extern void -js_FinalizeXML(JSContext *cx, JSXML *xml); - -extern JSObject * -js_ParseNodeToXMLObject(JSContext *cx, JSParseNode *pn); - -extern JSObject * -js_NewXMLObject(JSContext *cx, JSXMLClass xml_class); - -extern JSObject * -js_GetXMLObject(JSContext *cx, JSXML *xml); - -extern JS_FRIEND_DATA(JSXMLObjectOps) js_XMLObjectOps; -extern JS_FRIEND_DATA(JSClass) js_XMLClass; -extern JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass; -extern JS_FRIEND_DATA(JSExtendedClass) js_QNameClass; -extern JS_FRIEND_DATA(JSClass) js_AttributeNameClass; -extern JS_FRIEND_DATA(JSClass) js_AnyNameClass; - -/* - * Macros to test whether an object or a value is of type "xml" (per typeof). - * NB: jsapi.h must be included before any call to VALUE_IS_XML. - */ -#define OBJECT_IS_XML(cx,obj) ((obj)->map->ops == &js_XMLObjectOps.base) -#define VALUE_IS_XML(cx,v) (!JSVAL_IS_PRIMITIVE(v) && \ - OBJECT_IS_XML(cx, JSVAL_TO_OBJECT(v))) - -extern JSObject * -js_InitNamespaceClass(JSContext *cx, JSObject *obj); - -extern JSObject * -js_InitQNameClass(JSContext *cx, JSObject *obj); - -extern JSObject * -js_InitAttributeNameClass(JSContext *cx, JSObject *obj); - -extern JSObject * -js_InitAnyNameClass(JSContext *cx, JSObject *obj); - -extern JSObject * -js_InitXMLClass(JSContext *cx, JSObject *obj); - -extern JSObject * -js_InitXMLClasses(JSContext *cx, JSObject *obj); - -extern JSBool -js_GetFunctionNamespace(JSContext *cx, jsval *vp); - -extern JSBool -js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp); - -extern JSBool -js_SetDefaultXMLNamespace(JSContext *cx, jsval v); - -/* - * Return true if v is a XML QName object, or if it converts to a string that - * contains a valid XML qualified name (one containing no :), false otherwise. - * NB: This function is an infallible predicate, it hides exceptions. - */ -extern JSBool -js_IsXMLName(JSContext *cx, jsval v); - -extern JSBool -js_ToAttributeName(JSContext *cx, jsval *vp); - -extern JSString * -js_EscapeAttributeValue(JSContext *cx, JSString *str); - -extern JSString * -js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, - JSString *str2); - -extern JSString * -js_EscapeElementValue(JSContext *cx, JSString *str); - -extern JSString * -js_ValueToXMLString(JSContext *cx, jsval v); - -extern JSBool -js_GetAnyName(JSContext *cx, jsval *vp); - -extern JSBool -js_FindXMLProperty(JSContext *cx, jsval name, JSObject **objp, jsval *namep); - -extern JSBool -js_GetXMLProperty(JSContext *cx, JSObject *obj, jsval name, jsval *vp); - -extern JSBool -js_SetXMLProperty(JSContext *cx, JSObject *obj, jsval name, jsval *vp); - -extern JSBool -js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp); - -extern JSBool -js_DeleteXMLListElements(JSContext *cx, JSObject *listobj); - -extern JSBool -js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, jsval *vp); - -extern JSObject * -js_ValueToXMLObject(JSContext *cx, jsval v); - -extern JSObject * -js_ValueToXMLListObject(JSContext *cx, jsval v); - -extern JSObject * -js_CloneXMLObject(JSContext *cx, JSObject *obj); - -extern JSObject * -js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name, - JSString *value); - -extern JSString * -js_MakeXMLCDATAString(JSContext *cx, JSString *str); - -extern JSString * -js_MakeXMLCommentString(JSContext *cx, JSString *str); - -extern JSString * -js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str); - -#endif /* jsxml_h___ */ diff --git a/src/dom/js/prmjtime.c b/src/dom/js/prmjtime.c deleted file mode 100644 index 6e08423af..000000000 --- a/src/dom/js/prmjtime.c +++ /dev/null @@ -1,440 +0,0 @@ -/* -*- 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 -#include -#include "jstypes.h" -#include "jsutil.h" - -#include "jsprf.h" -#include "prmjtime.h" - -#define PRMJ_DO_MILLISECONDS 1 - -#ifdef XP_OS2 -#include -#endif -#ifdef XP_WIN -#include -#include -#endif - -#if defined(XP_UNIX) || defined(XP_BEOS) - -#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ -extern int gettimeofday(struct timeval *tv); -#endif - -#include - -#endif /* XP_UNIX */ - -#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 *)<ime,0,sizeof(ltime)); - ltime.tm_mday = 2; - ltime.tm_year = 70; -#ifdef SUNOS4 - ltime.tm_zone = 0; - ltime.tm_gmtoff = 0; - return timelocal(<ime) - (24 * 3600); -#else - return mktime(<ime) - (24L * 3600L); -#endif -#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_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 */ - 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 */ -} - -/* Get the DST timezone offset for the time passed in */ -JSInt64 -PRMJ_DSTOffset(JSInt64 local_time) -{ - JSInt64 us2s; - 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); -} - -/* 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_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 deleted file mode 100644 index b74fe845e..000000000 --- a/src/dom/js/prmjtime.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- 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 -#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 deleted file mode 100644 index 9301810e4..000000000 --- a/src/dom/js/resource.h +++ /dev/null @@ -1,15 +0,0 @@ -//{{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 diff --git a/src/dom/jsdombind.cpp b/src/dom/jsdombind.cpp deleted file mode 100644 index 2bb9d23c8..000000000 --- a/src/dom/jsdombind.cpp +++ /dev/null @@ -1,3959 +0,0 @@ - /** - * Phoebe DOM Implementation. - * - * This is a C++ approximation of the W3C DOM model, which follows - * fairly closely the specifications in the various .idl files, copies of - * which are provided for reference. Most important is this one: - * - * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2006-2007 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -/** - * This code provides the ECMAScript (Javascript) binding to the classes - * of the DOM Level 3 Core. This should provide DOM manipulation for - * most general-purpose XML and Document-like applications. More specialized - * applications like SVG should inherit from the core C++ classes, and also - * use the prototypes in this file as the basis for their bindings. - * - * To ensure that we at least attempt to bind ECMAScript to DOM - * as closely as possible to the standards, we will include the entire - * Appendix H of the XML Level 3 Core spec as annotations in this file. - * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/ecma-script-binding.html - */ - - - - #include "domimpl.h" - #include "jsdombind.h" - - #include - - - namespace org - { - namespace w3c - { - namespace dom - { - - -//######################################################################## -//# M E S S A G E S -//######################################################################## -void JavascriptDOMBinder::error(char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - fprintf(stderr, "JS error: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); -} - - -void JavascriptDOMBinder::trace(char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - fprintf(stdout, "JS: "); - vfprintf(stdout, fmt, args); - fprintf(stdout, "\n"); - va_end(args); -} - - - -//######################################################################## -//# U T I L I T Y -//######################################################################## - -//Use this for getting the JavascriptEngine from an object method -#define BINDER ((JavascriptDOMBinder *) JS_GetContextPrivate(cx)) - -#define NewObjectVal (CLASSNAME) \ - OBJECT_TO_JSVAL( JS_NewObject(cx, \ - &wrapperClassDef, \ - (JavascriptDOMBinder *) JS_GetContextPrivate(cx)->proto_## CLASSNAME, \ - (void *) priv) ); - -#define NewObjectPtrVal (CLASSNAME) \ - OBJECT_TO_JSVAL( JS_NewObject(cx, \ - &wrapperClassDef, \ - (JavascriptDOMBinder *) JS_GetContextPrivate(cx)->proto_## CLASSNAME, \ - (void *) new ## CLASSNAME ## Ptr (priv) )); - -/** - * The name of the property is an enumeration, so just return the value. - */ -static JSBool GetEnumProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) -{ - *vp = id; - return JS_TRUE; -} - - -static JSString *domToJString(JSContext *cx, const DOMString &s) -{ - JSString *str = JS_NewStringCopyN(cx, s.c_str(), s.size()); - return str; -} - -static DOMString jvToDomString(JSContext *cx, jsval s) -{ - JSString *jstr = JS_ValueToString(cx, s); - DOMString str = JS_GetStringBytes(jstr); - return str; -} - -static DOMString jToDomString(JSString *s) -{ - DOMString str = JS_GetStringBytes(s); - return str; -} - - -//######################################################################## -//# C L A S S E S -//######################################################################## - - -/** - * Appendix H: ECMAScript Language Binding - * - * This appendix contains the complete ECMAScript [ECMAScript] binding for the - * Level 3 Document Object Model Core definitions. H.1 ECMAScript Binding - * Extension - * - */ - -class Wrapper -{ -public: - - Wrapper(JSContext *context, JSObject *object) - { cx = context; obj = object; } - - virtual ~Wrapper() - {} - - virtual JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - virtual JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - virtual JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - -protected: - - JSContext *cx; - - JSObject *obj; - -}; - -/** - * WrapperProperty - Callback for retrieving properties - */ -static JSBool wrapperGetProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) -{ - Wrapper *w = (Wrapper *) JS_GetPrivate(cx, obj); - return w->getProperty(id, vp); -} - -/** - * JSSetProperty - Callback for setting properties - */ -static JSBool wrapperSetProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) -{ - Wrapper *w = (Wrapper *) JS_GetPrivate(cx, obj); - return w->setProperty(id, vp); -} - -/** - * JSConstructor - Callback for when a this object is created - */ -static JSBool wrapperConstructor(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - Wrapper *w = new Wrapper(cx, obj); - JSBool ret = w->init(argc, argv); - *rval = OBJECT_TO_JSVAL(obj); - return ret; -} - -/** - * JSDestructor - Callback for when a this object is destroyed - */ -static void wrapperDestructor(JSContext *cx, JSObject *obj) -{ - Wrapper *w = (Wrapper *) JS_GetPrivate(cx, obj); - delete w; -} - -static JSClass wrapperClassDef = -{ - "DOMWrapper", - JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, - wrapperGetProperty, wrapperSetProperty, - JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub, wrapperDestructor -}; - - -/** - * JSInit - Create a prototype for this class - */ -static JSObject* wrapperInit(JSContext *cx, JSObject *obj, - JSNative constructor, - JSPropertySpec *properties, - JSFunctionSpec *methods, - JSPropertySpec *staticProperties, - JSFunctionSpec *staticMethods, - JSObject *proto = NULL) -{ - JSObject *protoObj = JS_InitClass(cx, obj, proto, - &wrapperClassDef, - wrapperConstructor, 0, - properties, - methods, - staticProperties, - staticMethods); - return protoObj; -} - -#define WRAP_NAME(NAME) NAME ## _wrapper -#define CLASS_NAME(NAME) WRAP_NAME(NAME) - -#define CONST_NAME(NAME) NAME ## _constructor -#define CONSTRUCTOR_NAME(NAME) CONST_NAME(NAME) - -#define PT_NAME(NAME) NAME ## _properties -#define PROPERTY_TABLE(NAME) PT_NAME(NAME) - -#define M_NAME(NAME) NAME ## _method -#define METHOD_NAME(NAME) M_NAME(NAME) -#define MT_NAME(NAME) NAME ## _methods -#define METHOD_TABLE(NAME) MT_NAME(NAME) - -#define SPT_NAME(NAME) NAME ## _staticProperties -#define STATIC_PROPERTY_TABLE(NAME) SPT_NAME(NAME) - -#define SMT_NAME(NAME) NAME ## _staticMethods -#define STATIC_METHOD_TABLE(NAME) SMT_NAME(NAME) - -#define METHOD(NAME) \ -static JSBool NAME(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) \ -{ return ((CLASS_NAME(CURRENT_CLASS) *) JS_GetPrivate(cx, obj))->METHOD_NAME(NAME)(argc, argv, rval); } \ - JSBool METHOD_NAME(NAME)(uintN argc, jsval *argv, jsval *rval) - -#define CONSTRUCTOR(NAME) \ -static JSBool CONSTRUCTOR_NAME(NAME)(JSContext *cx, \ - JSObject *obj, uintN argc, \ - jsval *argv, jsval *rval) \ -{ \ - CLASS_NAME(NAME) *w = new CLASS_NAME(NAME)(cx, obj); \ - JSBool ret = w->init(argc, argv); \ - *rval = OBJECT_TO_JSVAL(obj); \ - return ret; \ -} - -#define CREATE_PROTO(NAME, cx, obj, proto) \ - JS_InitClass(cx, obj, proto, &wrapperClassDef, \ - CONSTRUCTOR_NAME(NAME), 0, \ - PROPERTY_TABLE(NAME), \ - METHOD_TABLE(NAME), \ - STATIC_PROPERTY_TABLE(NAME), \ - STATIC_METHOD_TABLE(NAME)); - -//######################################################################## -//# DOMImplementationRegistry -//######################################################################## - -/** - * This section defines the DOMImplementationRegistry object, discussed in - * Bootstrapping, for ECMAScript. - * - * - * Objects that implements the DOMImplementationRegistry interface - * - * DOMImplementationRegistry is a global variable which has the following - * functions: - * - * getDOMImplementation(features) - * This method returns the first registered object that implements - * the DOMImplementation interface and has the desired features, - * or null if none is found. The features parameter is a String. - * See also DOMImplementationSource.getDOMImplementation(). - * - * getDOMImplementationList(features) - * This method returns a DOMImplementationList list of registered - * object that implements the DOMImplementation interface and - * has the desired features. The features parameter is a String. - * See also DOMImplementationSource.getDOMImplementationList(). - * - * - */ -#define CURRENT_CLASS DOMImplementationRegistry - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { "getDOMImplementation", - CLASS_NAME(CURRENT_CLASS)::getDOMImplementation, 1, 0, 0 }, - { "getDOMImplementationList", - CLASS_NAME(CURRENT_CLASS)::getDOMImplementationList, 1, 0, 0 }, - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - -/** - * H.2 Other Core interfaces - */ - - - - -//######################################################################## -//# DOMException -//######################################################################## - -/** - * Properties of the DOMException Constructor function: - * - * DOMException.INDEX_SIZE_ERR - * The value of the constant DOMException.INDEX_SIZE_ERR is 1. - * DOMException.DOMSTRING_SIZE_ERR - * The value of the constant DOMException.DOMSTRING_SIZE_ERR is 2. - * DOMException.HIERARCHY_REQUEST_ERR - * The value of the constant DOMException.HIERARCHY_REQUEST_ERR is 3. - * DOMException.WRONG_DOCUMENT_ERR - * The value of the constant DOMException.WRONG_DOCUMENT_ERR is 4. - * DOMException.INVALID_CHARACTER_ERR - * The value of the constant DOMException.INVALID_CHARACTER_ERR is 5. - * DOMException.NO_DATA_ALLOWED_ERR - * The value of the constant DOMException.NO_DATA_ALLOWED_ERR is 6. - * DOMException.NO_MODIFICATION_ALLOWED_ERR - * The value of the constant DOMException.NO_MODIFICATION_ALLOWED_ERR is 7. - * DOMException.NOT_FOUND_ERR - * The value of the constant DOMException.NOT_FOUND_ERR is 8. - * DOMException.NOT_SUPPORTED_ERR - * The value of the constant DOMException.NOT_SUPPORTED_ERR is 9. - * DOMException.INUSE_ATTRIBUTE_ERR - * The value of the constant DOMException.INUSE_ATTRIBUTE_ERR is 10. - * DOMException.INVALID_STATE_ERR - * The value of the constant DOMException.INVALID_STATE_ERR is 11. - * DOMException.SYNTAX_ERR - * The value of the constant DOMException.SYNTAX_ERR is 12. - * DOMException.INVALID_MODIFICATION_ERR - * The value of the constant DOMException.INVALID_MODIFICATION_ERR is 13. - * DOMException.NAMESPACE_ERR - * The value of the constant DOMException.NAMESPACE_ERR is 14. - * DOMException.INVALID_ACCESS_ERR - * The value of the constant DOMException.INVALID_ACCESS_ERR is 15. - * DOMException.VALIDATION_ERR - * The value of the constant DOMException.VALIDATION_ERR is 16. - * DOMException.TYPE_MISMATCH_ERR - * The value of the constant DOMException.TYPE_MISMATCH_ERR is 17. - * - * Objects that implement the DOMException interface: - * - * Properties of objects that implement the DOMException interface: - * - * code - * This property is a Number. - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMException - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { "code", CLASS_NAME(CURRENT_CLASS)::prop_code, JSPROP_ENUMERATE }, - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { "INDEX_SIZE_ERR", DOMException::INDEX_SIZE_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "DOMSTRING_SIZE_ERR", DOMException::DOMSTRING_SIZE_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "HIERARCHY_REQUEST_ERR", DOMException::HIERARCHY_REQUEST_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "WRONG_DOCUMENT_ERR", DOMException::WRONG_DOCUMENT_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "INVALID_CHARACTER_ERR", DOMException::INVALID_CHARACTER_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "NO_DATA_ALLOWED_ERR", DOMException::NO_DATA_ALLOWED_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "NO_MODIFICATION_ALLOWED_ERR", DOMException::NO_MODIFICATION_ALLOWED_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "NOT_FOUND_ERR", DOMException::NOT_FOUND_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "NOT_SUPPORTED_ERR", DOMException::NOT_SUPPORTED_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "INUSE_ATTRIBUTE_ERR", DOMException::INUSE_ATTRIBUTE_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "INVALID_STATE_ERR", DOMException::INVALID_STATE_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "SYNTAX_ERR", DOMException::SYNTAX_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "INVALID_MODIFICATION_ERR", DOMException::INVALID_MODIFICATION_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "NAMESPACE_ERR", DOMException::NAMESPACE_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "INVALID_ACCESS_ERR", DOMException::INVALID_ACCESS_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "VALIDATION_ERR", DOMException::VALIDATION_ERR, - JSPROP_READONLY, GetEnumProperty }, - { "TYPE_MISMATCH_ERR", DOMException::TYPE_MISMATCH_ERR, - JSPROP_READONLY, GetEnumProperty }, - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - -//######################################################################## -//# DOMStringList -//######################################################################## - -/** - * Objects that implement the DOMStringList interface: - * - * Properties of objects that implement the DOMStringList interface: - * - * length - * This read-only property is a Number. - * - * Functions of objects that implement the DOMStringList interface: - * - * item(index) - * This function returns a String. - * The index parameter is a Number. - * Note: This object can also be dereferenced using square bracket - * notation (e.g. obj[1]). Dereferencing with an integer index - * is equivalent to invoking the item function with that index. - * - * contains(str) - * This function returns a Boolean. - * The str parameter is a String. - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMStringList - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - -//######################################################################## -//# NameList -//######################################################################## - -/** - * Objects that implement the NameList interface: - * - * Properties of objects that implement the NameList interface: - * - * length - * This read-only property is a Number. - * - * Functions of objects that implement the NameList interface: - * - * getName(index) - * This function returns a String. - * The index parameter is a Number. - * getNamespaceURI(index) - * This function returns a String. - * The index parameter is a Number. - * contains(str) - * This function returns a Boolean. - * The str parameter is a String. - * containsNS(namespaceURI, name) - * This function returns a Boolean. - * The namespaceURI parameter is a String. - * The name parameter is a String. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS NameList - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# DOMImplementationList -//######################################################################## - -/** - * Objects that implement the DOMImplementationList interface: - * - * Properties of objects that implement the DOMImplementationList interface: - * - * length - * This read-only property is a Number. - * - * Functions of objects that implement the DOMImplementationList interface: - * - * item(index) - * This function returns an object that implements the - * DOMImplementation interface. - * The index parameter is a Number. - * Note: This object can also be dereferenced using square bracket - * notation (e.g. obj[1]). Dereferencing with an integer index - * is equivalent to invoking the item function with that index. - * - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMImplementationList - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# DOMImplementationSource -//######################################################################## - -/** - * Objects that implement the DOMImplementationSource interface: - * - * Functions of objects that implement the DOMImplementationSource interface: - * - * getDOMImplementation(features) - * This function returns an object that implements the - * DOMImplementation interface. - * The features parameter is a String. - * getDOMImplementationList(features) - * This function returns an object that implements the - * DOMImplementationList interface. - * The features parameter is a String. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMImplementationSource - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - -//######################################################################## -//# DOMImplementation -//######################################################################## - -/** - * Objects that implement the DOMImplementation interface: - * - * Functions of objects that implement the DOMImplementation interface: - * - * hasFeature(feature, version) - * This function returns a Boolean. - * The feature parameter is a String. - * The version parameter is a String. - * createDocumentType(qualifiedName, publicId, systemId) - * This function returns an object that implements the - * DocumentType interface. - * The qualifiedName parameter is a String. - * The publicId parameter is a String. - * The systemId parameter is a String. - * This function can raise an object that implements the - * DOMException interface. - * createDocument(namespaceURI, qualifiedName, doctype) - * This function returns an object that implements the - * Document interface. - * The namespaceURI parameter is a String. - * The qualifiedName parameter is a String. - * The doctype parameter is an object that implements the - * DocumentType interface. - * This function can raise an object that implements the - * DOMException interface. - * getFeature(feature, version) - * This function returns an object that implements - * the Object interface. - * The feature parameter is a String. - * The version parameter is a String. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMImplementation - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - - -//######################################################################## -//# DocumentFragment -//######################################################################## - -/** - * Objects that implement the DocumentFragment interface: - * - * Objects that implement the DocumentFragment interface have all - * properties and functions of the Node interface. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DocumentFragment - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# Document -//######################################################################## - -/** - * Objects that implement the Document interface: - * - * Objects that implement the Document interface have all properties - * and functions of the Node interface as well as the properties - * and functions defined below. - * Properties of objects that implement the Document interface: - * - * - * doctype - * This read-only property is an object that implements - * the DocumentType interface. - * implementation - * This read-only property is an object that implements - * the DOMImplementation interface. - * documentElement - * This read-only property is an object that implements - * the Element interface. - * inputEncoding - * This read-only property is a String. - * xmlEncoding - * This read-only property is a String. - * xmlStandalone - * This property is a Boolean and can raise an object - * that implements the DOMException interface on setting. - * xmlVersion - * This property is a String and can raise an object - * that implements the DOMException interface on setting. - * strictErrorChecking - * This property is a Boolean. - * documentURI - * This property is a String. - * domConfig - * This read-only property is an object that implements - * the DOMConfiguration interface. - * - * - * Functions of objects that implement the Document interface: - * - * createElement(tagName) - * This function returns an object that implements - * the Element interface. - * The tagName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * createDocumentFragment() - * This function returns an object that implements - * the DocumentFragment interface. - * createTextNode(data) - * This function returns an object that implements - * the Text interface. - * The data parameter is a String. - * createComment(data) - * This function returns an object that implements - * the Comment interface. - * The data parameter is a String. - * createCDATASection(data) - * This function returns an object that implements - * the CDATASection interface. - * The data parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * createProcessingInstruction(target, data) - * This function returns an object that implements - * the ProcessingInstruction interface. - * The target parameter is a String. - * The data parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * createAttribute(name) - * This function returns an object that implements - * the Attr interface. - * The name parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * createEntityReference(name) - * This function returns an object that implements - * the EntityReference interface. - * The name parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * getElementsByTagName(tagname) - * This function returns an object that implements - * the NodeList interface. - * The tagname parameter is a String. - * importNode(importedNode, deep) - * This function returns an object that implements - * the Node interface. - * The importedNode parameter is an object that implements - * the Node interface. - * The deep parameter is a Boolean. - * This function can raise an object that implements - * the DOMException interface. - * createElementNS(namespaceURI, qualifiedName) - * This function returns an object that implements - * the Element interface. - * The namespaceURI parameter is a String. - * The qualifiedName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * createAttributeNS(namespaceURI, qualifiedName) - * This function returns an object that implements - * the Attr interface. - * The namespaceURI parameter is a String. - * The qualifiedName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * getElementsByTagNameNS(namespaceURI, localName) - * This function returns an object that implements - * the NodeList interface. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * getElementById(elementId) - * This function returns an object that implements - * the Element interface. - * The elementId parameter is a String. - * adoptNode(source) - * This function returns an object that implements - * the Node interface. - * The source parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * normalizeDocument() - * This function has no return value. - * renameNode(n, namespaceURI, qualifiedName) - * This function returns an object that implements - * the Node interface. - * The n parameter is an object that implements - * the Node interface. - * The namespaceURI parameter is a String. - * The qualifiedName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Document - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - - DocumentPtr doc; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - -//######################################################################## -//# Node -//######################################################################## - -/** - * Properties of the Node Constructor function: - * - * Node.ELEMENT_NODE - * The value of the constant Node.ELEMENT_NODE is 1. - * Node.ATTRIBUTE_NODE - * The value of the constant Node.ATTRIBUTE_NODE is 2. - * Node.TEXT_NODE - * The value of the constant Node.TEXT_NODE is 3. - * Node.CDATA_SECTION_NODE - * The value of the constant Node.CDATA_SECTION_NODE is 4. - * Node.ENTITY_REFERENCE_NODE - * The value of the constant Node.ENTITY_REFERENCE_NODE is 5. - * Node.ENTITY_NODE - * The value of the constant Node.ENTITY_NODE is 6. - * Node.PROCESSING_INSTRUCTION_NODE - * The value of the constant Node.PROCESSING_INSTRUCTION_NODE is 7. - * Node.COMMENT_NODE - * The value of the constant Node.COMMENT_NODE is 8. - * Node.DOCUMENT_NODE - * The value of the constant Node.DOCUMENT_NODE is 9. - * Node.DOCUMENT_TYPE_NODE - * The value of the constant Node.DOCUMENT_TYPE_NODE is 10. - * Node.DOCUMENT_FRAGMENT_NODE - * The value of the constant Node.DOCUMENT_FRAGMENT_NODE is 11. - * Node.NOTATION_NODE - * The value of the constant Node.NOTATION_NODE is 12. - * Node.DOCUMENT_POSITION_DISCONNECTED - * The value of the constant Node.DOCUMENT_POSITION_DISCONNECTED - * is 0x01. - * Node.DOCUMENT_POSITION_PRECEDING - * The value of the constant Node.DOCUMENT_POSITION_PRECEDING - * is 0x02. - * Node.DOCUMENT_POSITION_FOLLOWING - * The value of the constant Node.DOCUMENT_POSITION_FOLLOWING - * is 0x04. - * Node.DOCUMENT_POSITION_CONTAINS - * The value of the constant Node.DOCUMENT_POSITION_CONTAINS - * is 0x08. - * Node.DOCUMENT_POSITION_CONTAINED_BY - * The value of the constant Node.DOCUMENT_POSITION_CONTAINED_BY - * is 0x10. - * Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC - * The value of the constant Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC - * is 0x20. - * - * Objects that implement the Node interface: - * - * Properties of objects that implement the Node interface: - * - * nodeName - * This read-only property is a String. - * nodeValue - * This property is a String, can raise an object that implements - * the DOMException - * interface on setting and can raise an object that implements - * the DOMException - * interface on retrieval. - * nodeType - * This read-only property is a Number. - * parentNode - * This read-only property is an object that implements - * the Node interface. - * childNodes - * This read-only property is an object that implements - * the NodeList interface. - * firstChild - * This read-only property is an object that implements - * the Node interface. - * lastChild - * This read-only property is an object that implements - * the Node interface. - * previousSibling - * This read-only property is an object that implements - * the Node interface. - * nextSibling - * This read-only property is an object that implements - * the Node interface. - * attributes - * This read-only property is an object that implements - * the NamedNodeMap interface. - * ownerDocument - * This read-only property is an object that implements - * the Document interface. - * namespaceURI - * This read-only property is a String. - * prefix - * This property is a String and can raise an object - * that implements the DOMException interface on setting. - * localName - * This read-only property is a String. - * baseURI - * This read-only property is a String. - * textContent - * This property is a String, can raise an object that implements - * the DOMException interface on setting and can raise - * an object that implements the DOMException interface - * on retrieval. - * - * - * Functions of objects that implement the Node interface: - * - * insertBefore(newChild, refChild) - * This function returns an object that implements - * the Node interface. - * The newChild parameter is an object that implements - * the Node interface. - * The refChild parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * replaceChild(newChild, oldChild) - * This function returns an object that implements - * the Node interface. - * The newChild parameter is an object that implements - * the Node interface. - * The oldChild parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * removeChild(oldChild) - * This function returns an object that implements - * the Node interface. - * The oldChild parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * appendChild(newChild) - * This function returns an object that implements - * the Node interface. - * The newChild parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * hasChildNodes() - * This function returns a Boolean. - * cloneNode(deep) - * This function returns an object that implements - * the Node interface. - * The deep parameter is a Boolean. - * normalize() - * This function has no return value. - * isSupported(feature, version) - * This function returns a Boolean. - * The feature parameter is a String. - * The version parameter is a String. - * hasAttributes() - * This function returns a Boolean. - * compareDocumentPosition(other) - * This function returns a Number. - * The other parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * isSameNode(other) - * This function returns a Boolean. - * The other parameter is an object that implements - * the Node interface. - * lookupPrefix(namespaceURI) - * This function returns a String. - * The namespaceURI parameter is a String. - * isDefaultNamespace(namespaceURI) - * This function returns a Boolean. - * The namespaceURI parameter is a String. - * lookupNamespaceURI(prefix) - * This function returns a String. - * The prefix parameter is a String. - * isEqualNode(arg) - * This function returns a Boolean. - * The arg parameter is an object that implements - * the Node interface. - * getFeature(feature, version) - * This function returns an object that implements - * the Object interface. - * The feature parameter is a String. - * The version parameter is a String. - * setUserData(key, data, handler) - * This function returns an object that implements - * the any type interface. - * The key parameter is a String. - * The data parameter is an object that implements - * the any type interface. - * The handler parameter is an object that implements - * the UserDataHandler interface. - * getUserData(key) - * This function returns an object that implements - * the any type interface. - * The key parameter is a String. - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Node - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# NodeList -//######################################################################## - -/** - * Objects that implement the NodeList interface: - * - * Properties of objects that implement the NodeList interface: - * - * length - * This read-only property is a Number. - * - * Functions of objects that implement the NodeList interface: - * - * item(index) - * This function returns an object that implements - * the Node interface. - * The index parameter is a Number. - * Note: This object can also be dereferenced using square - * bracket notation (e.g. obj[1]). Dereferencing with - * an integer index is equivalent to invoking the item - * function with that index. - * - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS NodeList - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - -//######################################################################## -//# NamedNodeMap -//######################################################################## - -/** - * Objects that implement the NamedNodeMap interface: - * - * Properties of objects that implement the NamedNodeMap interface: - * - * length - * This read-only property is a Number. - * - * Functions of objects that implement the NamedNodeMap interface: - * - * getNamedItem(name) - * This function returns an object that implements - * the Node interface. - * The name parameter is a String. - * setNamedItem(arg) - * This function returns an object that implements - * the Node interface. - * The arg parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * removeNamedItem(name) - * This function returns an object that implements - * the Node interface. - * The name parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * item(index) - * This function returns an object that implements - * the Node interface. - * The index parameter is a Number. - * Note: This object can also be dereferenced using square - * bracket notation (e.g. obj[1]). Dereferencing with - * an integer index is equivalent to invoking the item - * function with that index. - * getNamedItemNS(namespaceURI, localName) - * This function returns an object that implements - * the Node interface. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * setNamedItemNS(arg) - * This function returns an object that implements - * the Node interface. - * The arg parameter is an object that implements - * the Node interface. - * This function can raise an object that implements - * the DOMException interface. - * removeNamedItemNS(namespaceURI, localName) - * This function returns an object that implements - * the Node interface. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - */ - - -#undef CURRENT_CLASS -#define CURRENT_CLASS NamedNodeMap - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# CharacterData -//######################################################################## - -/** - * Objects that implement the CharacterData interface: - * - * Objects that implement the CharacterData interface have all - * properties and functions of the Node interface as well as - * the properties and functions defined below. Properties - * of objects that implement the CharacterData interface: - * - * - * data - * This property is a String, can raise an object - * that implements the DOMException interface on setting - * and can raise an object that implements the DOMException - * interface on retrieval. - * length - * This read-only property is a Number. - * - * Functions of objects that implement the CharacterData interface: - * - * substringData(offset, count) - * This function returns a String. - * The offset parameter is a Number. - * The count parameter is a Number. - * This function can raise an object that implements - * the DOMException interface. - * appendData(arg) - * This function has no return value. - * The arg parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * insertData(offset, arg) - * This function has no return value. - * The offset parameter is a Number. - * The arg parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * deleteData(offset, count) - * This function has no return value. - * The offset parameter is a Number. - * The count parameter is a Number. - * This function can raise an object that implements - * the DOMException interface. - * replaceData(offset, count, arg) - * This function has no return value. - * The offset parameter is a Number. - * The count parameter is a Number. - * The arg parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS CharacterData - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - - -//######################################################################## -//# Attr -//######################################################################## - -/** - * Objects that implement the Attr interface: - * - * Objects that implement the Attr interface have all properties - * and functions of the Node interface as well as the properties - * and functions defined below. - * Properties of objects that implement the Attr interface: - * - * - * name - * This read-only property is a String. - * specified - * This read-only property is a Boolean. - * value - * This property is a String and can raise an object - * that implements the DOMException interface on setting. - * ownerElement - * This read-only property is an object that implements - * the Element interface. - * schemaTypeInfo - * This read-only property is an object that implements - * the TypeInfo interface. - * isId - * This read-only property is a Boolean. - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Attr - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - -//######################################################################## -//# Element -//######################################################################## - -/** - * Objects that implement the Element interface: - * - * Objects that implement the Element interface have all properties - * and functions of the Node interface as well as the properties - * and functions defined below. - * Properties of objects that implement the Element interface: - * - * - * tagName - * This read-only property is a String. - * schemaTypeInfo - * This read-only property is an object that implements - * the TypeInfo interface. - * - * Functions of objects that implement the Element interface: - * - * getAttribute(name) - * This function returns a String. - * The name parameter is a String. - * setAttribute(name, value) - * This function has no return value. - * The name parameter is a String. - * The value parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * removeAttribute(name) - * This function has no return value. - * The name parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * getAttributeNode(name) - * This function returns an object that implements - * the Attr interface. - * The name parameter is a String. - * setAttributeNode(newAttr) - * This function returns an object that implements - * the Attr interface. - * The newAttr parameter is an object that implements - * the Attr interface. - * This function can raise an object that implements - * the DOMException interface. - * removeAttributeNode(oldAttr) - * This function returns an object that implements - * the Attr interface. - * The oldAttr parameter is an object that implements - * the Attr interface. - * This function can raise an object that implements - * the DOMException interface. - * getElementsByTagName(name) - * This function returns an object that implements - * the NodeList interface. - * The name parameter is a String. - * getAttributeNS(namespaceURI, localName) - * This function returns a String. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * setAttributeNS(namespaceURI, qualifiedName, value) - * This function has no return value. - * The namespaceURI parameter is a String. - * The qualifiedName parameter is a String. - * The value parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * removeAttributeNS(namespaceURI, localName) - * This function has no return value. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * getAttributeNodeNS(namespaceURI, localName) - * This function returns an object that implements - * the Attr interface. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * setAttributeNodeNS(newAttr) - * This function returns an object that implements - * the Attr interface. - * The newAttr parameter is an object that implements - * the Attr interface. - * This function can raise an object that implements - * the DOMException interface. - * getElementsByTagNameNS(namespaceURI, localName) - * This function returns an object that implements - * the NodeList interface. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * hasAttribute(name) - * This function returns a Boolean. - * The name parameter is a String. - * hasAttributeNS(namespaceURI, localName) - * This function returns a Boolean. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * setIdAttribute(name, isId) - * This function has no return value. - * The name parameter is a String. - * The isId parameter is a Boolean. - * This function can raise an object that implements - * the DOMException interface. - * setIdAttributeNS(namespaceURI, localName, isId) - * This function has no return value. - * The namespaceURI parameter is a String. - * The localName parameter is a String. - * The isId parameter is a Boolean. - * This function can raise an object that implements - * the DOMException interface. - * setIdAttributeNode(idAttr, isId) - * This function has no return value. - * The idAttr parameter is an object that implements - * the Attr interface. - * The isId parameter is a Boolean. - * This function can raise an object that implements - * the DOMException interface. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Element - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# Text -//######################################################################## - -/** - * Objects that implement the Text interface: - * - * Objects that implement the Text interface have all properties - * and functions of the CharacterData interface as well as - * the properties and functions defined below. Properties of objects - * that implement the Text interface: - * - * - * isElementContentWhitespace - * This read-only property is a Boolean. - * wholeText - * This read-only property is a String. - * - * Functions of objects that implement the Text interface: - * - * splitText(offset) - * This function returns an object that implements - * the Text interface. - * The offset parameter is a Number. - * This function can raise an object that implements - * the DOMException interface. - * replaceWholeText(content) - * This function returns an object that implements - * the Text interface. - * The content parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Text - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# Comment -//######################################################################## - -/** - * Objects that implement the Comment interface: - * - * Objects that implement the Comment interface have all properties - * and functions of the CharacterData interface. - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Comment - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - -//######################################################################## -//# TypeInfo -//######################################################################## - -/** - * Properties of the TypeInfo Constructor function: - * - * TypeInfo.DERIVATION_RESTRICTION - * The value of the constant TypeInfo.DERIVATION_RESTRICTION - * is 0x00000001. - * TypeInfo.DERIVATION_EXTENSION - * The value of the constant TypeInfo.DERIVATION_EXTENSION - * is 0x00000002. - * TypeInfo.DERIVATION_UNION - * The value of the constant TypeInfo.DERIVATION_UNION - * is 0x00000004. - * TypeInfo.DERIVATION_LIST - * The value of the constant TypeInfo.DERIVATION_LIST - * is 0x00000008. - * - * Objects that implement the TypeInfo interface: - * - * Properties of objects that implement the TypeInfo interface: - * - * typeName - * This read-only property is a String. - * typeNamespace - * This read-only property is a String. - * - * Functions of objects that implement the TypeInfo interface: - * - * isDerivedFrom(typeNamespaceArg, typeNameArg, derivationMethod) - * This function returns a Boolean. - * The typeNamespaceArg parameter is a String. - * The typeNameArg parameter is a String. - * The derivationMethod parameter is a Number. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS TypeInfo - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - - - -//######################################################################## -//# UserDataHandler -//######################################################################## - -/** - * Properties of the UserDataHandler Constructor function: - * - * UserDataHandler.NODE_CLONED - * The value of the constant UserDataHandler.NODE_CLONED is 1. - * UserDataHandler.NODE_IMPORTED - * The value of the constant UserDataHandler.NODE_IMPORTED is 2. - * UserDataHandler.NODE_DELETED - * The value of the constant UserDataHandler.NODE_DELETED is 3. - * UserDataHandler.NODE_RENAMED - * The value of the constant UserDataHandler.NODE_RENAMED is 4. - * UserDataHandler.NODE_ADOPTED - * The value of the constant UserDataHandler.NODE_ADOPTED is 5. - * - * UserDataHandler function: - * This function has no return value. - * The first parameter is a Number. - * The second parameter is a String. - * The third parameter is an object that implements the any - * type interface. - * The fourth parameter is an object that implements the Node - * interface. - * The fifth parameter is an object that implements the Node interface. - * Properties of the DOMError Constructor function: - * - * - * DOMError.SEVERITY_WARNING - * The value of the constant DOMError.SEVERITY_WARNING is 1. - * DOMError.SEVERITY_ERROR - * The value of the constant DOMError.SEVERITY_ERROR is 2. - * DOMError.SEVERITY_FATAL_ERROR - * The value of the constant DOMError.SEVERITY_FATAL_ERROR is 3. - */ - - -#undef CURRENT_CLASS -#define CURRENT_CLASS UserDataHandler - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - -//######################################################################## -//# DOMError -//######################################################################## - -/** - * Objects that implement the DOMError interface: - * - * Properties of objects that implement the DOMError interface: - * - * severity - * This read-only property is a Number. - * message - * This read-only property is a String. - * type - * This read-only property is a String. - * relatedException - * This read-only property is an object that implements - * the Object interface. - * relatedData - * This read-only property is an object that implements - * the Object interface. - * location - * This read-only property is an object that implements - * the DOMLocator interface. - * - * DOMErrorHandler function: - * This function returns a Boolean. - * The parameter is an object that implements the - * DOMError interface. - * - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMError - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# DOMLocator -//######################################################################## - -/** - * Objects that implement the DOMLocator interface: - * - * Properties of objects that implement the DOMLocator interface: - * - * lineNumber - * This read-only property is a Number. - * columnNumber - * This read-only property is a Number. - * byteOffset - * This read-only property is a Number. - * utf16Offset - * This read-only property is a Number. - * relatedNode - * This read-only property is an object that implements - * the Node interface. - * uri - * This read-only property is a String. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMLocator - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - - -//######################################################################## -//# DOMConfiguration -//######################################################################## - -/** - * Objects that implement the DOMConfiguration interface: - * - * Properties of objects that implement the DOMConfiguration interface: - * - * parameterNames - * This read-only property is an object that implements - * the DOMStringList interface. - * - * Functions of objects that implement the DOMConfiguration interface: - * - * setParameter(name, value) - * This function has no return value. - * The name parameter is a String. - * The value parameter is an object that implements - * the any type interface. - * This function can raise an object that implements - * the DOMException interface. - * getParameter(name) - * This function returns an object that implements - * the any type interface. - * The name parameter is a String. - * This function can raise an object that implements - * the DOMException interface. - * canSetParameter(name, value) - * This function returns a Boolean. - * The name parameter is a String. - * The value parameter is an object that implements - * the any type interface. - */ - - -#undef CURRENT_CLASS -#define CURRENT_CLASS DOMConfiguration - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - -//######################################################################## -//# CDATASection -//######################################################################## - -/** - * Objects that implement the CDATASection interface: - * - * Objects that implement the CDATASection interface - * have all properties and functions of the Text interface. - * - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS CDATASection - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - - -//######################################################################## -//# DocumentType -//######################################################################## - -/** - * Objects that implement the DocumentType interface: - * - * Objects that implement the DocumentType interface have all - * properties and functions of the Node interface as well as - * the properties and functions defined below. - * Properties of objects that implement the DocumentType interface: - * - * - * name - * This read-only property is a String. - * entities - * This read-only property is an object that implements - * the NamedNodeMap interface. - * notations - * This read-only property is an object that implements - * the NamedNodeMap interface. - * publicId - * This read-only property is a String. - * systemId - * This read-only property is a String. - * internalSubset - * This read-only property is a String. - */ - - -#undef CURRENT_CLASS -#define CURRENT_CLASS DocumentType - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - -//######################################################################## -//# Notation -//######################################################################## - -/** - * Objects that implement the Notation interface: - * - * Objects that implement the Notation interface have all - * properties and functions of the Node interface as well as - * the properties and functions defined below. - * Properties of objects that implement the Notation interface: - * - * - * publicId - * This read-only property is a String. - * systemId - * This read-only property is a String. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Notation - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - -//######################################################################## -//# Entity -//######################################################################## - -/** - * Objects that implement the Entity interface: - * - * Objects that implement the Entity interface have all properties - * and functions of the Node interface as well as the properties - * and functions defined below. - * Properties of objects that implement the Entity interface: - * - * - * publicId - * This read-only property is a String. - * systemId - * This read-only property is a String. - * notationName - * This read-only property is a String. - * inputEncoding - * This read-only property is a String. - * xmlEncoding - * This read-only property is a String. - * xmlVersion - * This read-only property is a String. - */ - -#undef CURRENT_CLASS -#define CURRENT_CLASS Entity - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - - -//######################################################################## -//# EntityReference -//######################################################################## - -/** - * Objects that implement the EntityReference interface: - * - * Objects that implement the EntityReference interface have all - * properties and functions of the Node interface. - * - */ - - -#undef CURRENT_CLASS -#define CURRENT_CLASS EntityReference - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -//######################################################################## -//# ProcessingInstruction -//######################################################################## - -/** - * Objects that implement the ProcessingInstruction interface: - * - * Objects that implement the ProcessingInstruction interface - * have all properties and functions of the Node interface - * as well as the properties and functions defined below. - * Properties of objects that implement the ProcessingInstruction - * interface: - * - * target - * This read-only property is a String. - * data - * This property is a String and can raise an object - * that implements the DOMException interface on setting. - * - */ - - -#undef CURRENT_CLASS -#define CURRENT_CLASS ProcessingInstruction - -class CLASS_NAME(CURRENT_CLASS) : public Wrapper -{ -public: - - CLASS_NAME(CURRENT_CLASS)(JSContext*cx, JSObject *obj) - : Wrapper(cx, obj) - {} - - ~CLASS_NAME(CURRENT_CLASS)() - {} - - JSBool init(uintN argc, jsval *argv) - { - return JS_TRUE; - } - - JSBool getProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - JSBool setProperty(jsval id, jsval *vp) - { - return JS_FALSE; - } - - /** - * - */ - METHOD(getDOMImplementation) - { - return JS_FALSE; - } - - - /** - * - */ - METHOD(getDOMImplementationList) - { - return JS_FALSE; - } - - enum - { - prop_code - }; - -}; - - - - -JSPropertySpec PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSPropertySpec STATIC_PROPERTY_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - -JSFunctionSpec STATIC_METHOD_TABLE(CURRENT_CLASS)[] = -{ - { 0 } -}; - - -CONSTRUCTOR ( CURRENT_CLASS ) - - - - - - -/** - * Note: In addition of having DOMConfiguration parameters - * exposed to the application using the setParameter - * and getParameter, those parameters are also exposed - * as ECMAScript properties on the DOMConfiguration object. - * The name of the parameter is converted into a property name - * using a camel-case convention: - * the character '-' (HYPHEN-MINUS) is removed - * and the following character is - * being replaced by its uppercase equivalent. - */ - - - - - -//######################################################################## -//# M A I N B I N D I N G -//######################################################################## - -bool JavascriptDOMBinder::createClasses() -{ - void *savedContext = JS_GetContextPrivate(cx); - JS_SetContextPrivate(cx, (void *)this); - - proto_Node = - CREATE_PROTO(Node, cx, globalObj, NULL); - proto_CharacterData = - CREATE_PROTO(CharacterData, cx, globalObj, proto_Node); - proto_Text = - CREATE_PROTO(Text, cx, globalObj, proto_CharacterData); - proto_CDATASection = - CREATE_PROTO(CDATASection, cx, globalObj, proto_Text); - proto_Document = - CREATE_PROTO(Document, cx, globalObj, proto_CDATASection); - - JS_SetContextPrivate(cx, savedContext); - return true; -} - - -JSObject *JavascriptDOMBinder::wrapDocument(const Document *doc) -{ - if (!doc) - { - error("wrapDocument: null document parameter"); - return NULL; - } - - JSObject *jsdoc = JS_NewObject(cx, &wrapperClassDef, - proto_Document, NULL); - - //Wrap around the document... done! - CLASS_NAME(Document) *docWrap = new CLASS_NAME(Document)(cx, globalObj); - docWrap->doc = doc; - JS_SetPrivate(cx, jsdoc, (void *)docWrap); - - return jsdoc; -} - - - - -} // namespace dom -} // namespace w3c -} // namespace org - -//######################################################################## -//# E N D O F F I L E -//######################################################################## - diff --git a/src/dom/jsdombind.h b/src/dom/jsdombind.h deleted file mode 100644 index eb2f54659..000000000 --- a/src/dom/jsdombind.h +++ /dev/null @@ -1,163 +0,0 @@ -#ifndef __JSDOMBIND_H__ -#define __JSDOMBIND_H__ -/** - * Phoebe DOM Implementation. - * - * This is a C++ approximation of the W3C DOM model, which follows - * fairly closely the specifications in the various .idl files, copies of - * which are provided for reference. Most important is this one: - * - * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2006-2007 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "jsengine.h" - - -namespace org -{ -namespace w3c -{ -namespace dom -{ - - -/** - * Wrap the W3C DOM Core classes around a JavascriptEngine. - */ -class JavascriptDOMBinder -{ -public: - - /** - * Constructor - */ - JavascriptDOMBinder(JavascriptEngine &someEngine) - : engine(someEngine) - { init(); } - - - /** - * Destructor - */ - virtual ~JavascriptDOMBinder() - { } - - - JSObject *wrapDocument(const Document *doc); - - /** - * Bind with the basic DOM classes - */ - bool createClasses(); - - JSObject *proto_Attr; - JSObject *proto_CDATASection; - JSObject *proto_CharacterData; - JSObject *proto_Comment; - JSObject *proto_Document; - JSObject *proto_DocumentFragment; - JSObject *proto_DocumentType; - JSObject *proto_DOMConfiguration; - JSObject *proto_DOMError; - JSObject *proto_DOMException; - JSObject *proto_DOMImplementation; - JSObject *proto_DOMImplementationList; - JSObject *proto_DOMImplementationRegistry; - JSObject *proto_DOMImplementationSource; - JSObject *proto_DOMLocator; - JSObject *proto_DOMStringList; - JSObject *proto_Element; - JSObject *proto_Entity; - JSObject *proto_EntityReference; - JSObject *proto_NamedNodeMap; - JSObject *proto_NameList; - JSObject *proto_Node; - JSObject *proto_NodeList; - JSObject *proto_Notation; - JSObject *proto_ProcessingInstruction; - JSObject *proto_Text; - JSObject *proto_TypeInfo; - JSObject *proto_UserDataHandler; - -private: - - void init() - { - rt = engine.getRuntime(); - cx = engine.getContext(); - globalObj = engine.getGlobalObject(); - } - - /** - * Assignment operator. Let's keep this private for now, - * as we want one Spidermonkey runtime per c++ shell - */ - JavascriptDOMBinder &operator=(const JavascriptDOMBinder &other) - { assign(other); return *this; } - - void assign(const JavascriptDOMBinder &other) - { - rt = other.rt; - cx = other.cx; - globalObj = other.globalObj; - } - - - /** - * Ouput a printf-formatted error message - */ - void error(char *fmt, ...) - #ifdef G_GNUC_PRINTF - G_GNUC_PRINTF(2, 3) - #endif - ; - - /** - * Ouput a printf-formatted error message - */ - void trace(char *fmt, ...) - #ifdef G_GNUC_PRINTF - G_GNUC_PRINTF(2, 3) - #endif - ; - - JSRuntime *rt; - - JSContext *cx; - - JSObject *globalObj; - - - - JavascriptEngine &engine; -}; - - - -} // namespace dom -} // namespace w3c -} // namespace org - - -#endif /* __JSDOMBIND_H__ */ - - diff --git a/src/dom/jsengine.cpp b/src/dom/jsengine.cpp deleted file mode 100644 index 680d5a671..000000000 --- a/src/dom/jsengine.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/** - * Phoebe DOM Implementation. - * - * This is a C++ approximation of the W3C DOM model, which follows - * fairly closely the specifications in the various .idl files, copies of - * which are provided for reference. Most important is this one: - * - * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2006-2007 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include "jsengine.h" -#include "jsdombind.h" - -#include -#include - -namespace org -{ -namespace w3c -{ -namespace dom -{ - - - -//######################################################################## -//# M E S S A G E S -//######################################################################## -void JavascriptEngine::error(char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - fprintf(stderr, "JS error: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); -} - - -void JavascriptEngine::trace(char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - fprintf(stdout, "JS: "); - vfprintf(stdout, fmt, args); - fprintf(stdout, "\n"); - va_end(args); -} - - - -static JSClass globalClass = -{ - "Global", 0, - JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub, JS_FinalizeStub -}; - - -//A couple of shell functions from js.c -static JSBool shellf_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 JSBool shellf_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(stdout, "%s%s", i ? " " : "", JS_GetStringBytes(str)); - } - n++; - if (n) - fputc('\n', stdout); - return JS_TRUE; -} - - -static JSFunctionSpec shell_functions[] = -{ - {"version", shellf_version, 0}, - {"print", shellf_print, 0}, - { 0 } -}; - - - -bool JavascriptEngine::startup() -{ - /* You need a runtime and one or more contexts to do anything with JS. */ - rt = JS_NewRuntime(0x400000L); - if (!rt) - { - error("can't create JavaScript runtime"); - return false; - } - - cx = JS_NewContext(rt, 8192); - if (!cx) - { - error("can't create JavaScript context"); - return false; - } - - JS_SetContextPrivate(cx, (void *)this); - - - JS_SetErrorReporter(cx, errorReporter); - - /* - * The context definitely wants a global object, in order to have standard - * classes and functions like Date and parseInt. See below for details on - * JS_NewObject. - */ - - globalObj = JS_NewObject(cx, &globalClass, 0, 0); - if (!globalObj) - { - error("Could not init global object"); - return false; - } - - if (!JS_InitStandardClasses(cx, globalObj)) - { - error("Could not init standard classes"); - return false; - } - - if (!JS_DefineFunctions(cx, globalObj, shell_functions)) - { - error("Could not add extra functions"); - return false; - } - - if (!createClasses()) - { - error("Could not create local classes"); - return false; - } - - return true; -} - - - - -bool JavascriptEngine::shutdown() -{ - - return true; -} - - -/** - * Evaluate a script - */ -bool JavascriptEngine::evaluate(const DOMString &script) -{ - const char *cscript = script.c_str(); - int length = script.size(); - jsval rval; - JSBool ret = JS_EvaluateScript(cx, globalObj, - cscript, length, "buffer", - 0, &rval); - - if (ret == JS_FALSE) - { - return false; - } - - return true; -} - -/** - * Evaluate a script from a file - */ -bool JavascriptEngine::evaluateFile(const DOMString &fileName) -{ - FILE *f = fopen(fileName.c_str(), "r"); - if (!f) - { - error("Could not open '%s' for reading", fileName.c_str()); - return false; - } - DOMString script; - while (true) - { - int ch = fgetc(f); - if (ch < 0) - break; - script.push_back((char)ch); - } - fclose(f); - - const char *cscript = script.c_str(); - int length = script.size(); - jsval rval; - JSBool ret = JS_EvaluateScript(cx, globalObj, - cscript, length, fileName.c_str(), - 0, &rval); - - if (ret == JS_FALSE) - { - return false; - } - - return true; -} - -/** - * Bind with the basic DOM classes - */ -bool JavascriptEngine::createClasses() -{ - JavascriptDOMBinder binder(*this); - binder.createClasses(); - return true; -} - - - -} // namespace dom -} // namespace w3c -} // namespace org - - -//######################################################################## -//# E N D O F F I L E -//######################################################################## - diff --git a/src/dom/jsengine.h b/src/dom/jsengine.h deleted file mode 100644 index b7bbe2bc1..000000000 --- a/src/dom/jsengine.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef __JSENGINE_H__ -#define __JSENGINE_H__ -/** - * Phoebe DOM Implementation. - * - * This is a C++ approximation of the W3C DOM model, which follows - * fairly closely the specifications in the various .idl files, copies of - * which are provided for reference. Most important is this one: - * - * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2006-2007 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "dom.h" -#include "js/jsapi.h" - - -namespace org -{ -namespace w3c -{ -namespace dom -{ - -/** - * Encapsulate a Spidermonkey JavaScript interpreter. Init classes, then - * wrap around any objects that are needed. - */ -class JavascriptEngine -{ -public: - - /** - * Constructor - */ - JavascriptEngine() - { startup(); } - - - /** - * Destructor - */ - virtual ~JavascriptEngine() - { shutdown(); } - - /** - * Evaluate a script - */ - bool evaluate(const DOMString &script); - - /** - * Evaluate a script from a file - */ - bool evaluateFile(const DOMString &script); - - - /** - * Return the runtime of the wrapped JS engine - */ - JSRuntime *getRuntime() - { return rt; } - - /** - * Return the current context of the wrapped JS engine - */ - JSContext *getContext() - { return cx; } - - /** - * Return the current global object of the wrapped JS engine - */ - JSObject *getGlobalObject() - { return globalObj; } - - -private: - - /** - * Startup the javascript engine - */ - bool startup(); - - /** - * Shutdown the javascript engine - */ - bool shutdown(); - - void init() - { - rt = NULL; - cx = NULL; - globalObj = NULL; - } - - /** - * Assignment operator. Let's keep this private for now, - * as we want one Spidermonkey runtime per c++ shell - */ - JavascriptEngine &operator=(const JavascriptEngine &other) - { assign(other); return *this; } - - void assign(const JavascriptEngine &other) - { - rt = other.rt; - cx = other.cx; - globalObj = other.globalObj; - } - - /** - * Bind with the basic DOM classes - */ - bool createClasses(); - - /** - * Ouput a printf-formatted error message - */ - void error(char *fmt, ...) - #ifdef G_GNUC_PRINTF - G_GNUC_PRINTF(2, 3) - #endif - ; - - /** - * Ouput a printf-formatted error message - */ - void trace(char *fmt, ...) - #ifdef G_GNUC_PRINTF - G_GNUC_PRINTF(2, 3) - #endif - ; - - JSRuntime *rt; - - JSContext *cx; - - JSObject *globalObj; - - static void errorReporter(JSContext *cx, - const char *message, JSErrorReport *report) - { - JavascriptEngine *engine = - (JavascriptEngine *) JS_GetContextPrivate(cx); - engine->error((char *)message); - } - - - - -}; - - - -} // namespace dom -} // namespace w3c -} // namespace org - - -#endif /* __JSENGINE_H__ */ - - -- 2.30.2