Code

update JS
authorishmal <ishmal@users.sourceforge.net>
Mon, 5 Mar 2007 10:34:59 +0000 (10:34 +0000)
committerishmal <ishmal@users.sourceforge.net>
Mon, 5 Mar 2007 10:34:59 +0000 (10:34 +0000)
93 files changed:
src/dom/Makefile.mingw
src/dom/js/README.ink [new file with mode: 0644]
src/dom/js/fdlibm/.cvsignore [deleted file]
src/dom/js/fdlibm/Makefile.in [deleted file]
src/dom/js/fdlibm/Makefile.ref [deleted file]
src/dom/js/fdlibm/e_rem_pio2.c
src/dom/js/fdlibm/fdlibm.h
src/dom/js/fdlibm/fdlibm.mak [deleted file]
src/dom/js/fdlibm/fdlibm.mdp [deleted file]
src/dom/js/fdlibm/k_cos.c
src/dom/js/js.c
src/dom/js/js.mak [deleted file]
src/dom/js/js.msg
src/dom/js/jsapi.c
src/dom/js/jsapi.h
src/dom/js/jsarena.c
src/dom/js/jsarena.h
src/dom/js/jsarray.c
src/dom/js/jsarray.h
src/dom/js/jsatom.c
src/dom/js/jsatom.h
src/dom/js/jsbool.c
src/dom/js/jsbool.h
src/dom/js/jsclist.h
src/dom/js/jscntxt.c
src/dom/js/jscntxt.h
src/dom/js/jsconfig.h
src/dom/js/jsconfig.mk [deleted file]
src/dom/js/jscpucfg.c
src/dom/js/jscpucfg.h
src/dom/js/jsdate.c
src/dom/js/jsdate.h
src/dom/js/jsdbgapi.c
src/dom/js/jsdbgapi.h
src/dom/js/jsdhash.c
src/dom/js/jsdhash.h
src/dom/js/jsdtoa.c
src/dom/js/jsemit.c
src/dom/js/jsemit.h
src/dom/js/jsexn.c
src/dom/js/jsfile.c
src/dom/js/jsfile.h
src/dom/js/jsfile.msg
src/dom/js/jsfun.c
src/dom/js/jsfun.h
src/dom/js/jsgc.c
src/dom/js/jsgc.h
src/dom/js/jshash.c
src/dom/js/jsinterp.c
src/dom/js/jsinterp.h
src/dom/js/jslibmath.h
src/dom/js/jslock.c
src/dom/js/jslock.h
src/dom/js/jslocko.asm
src/dom/js/jslog2.c
src/dom/js/jslong.c
src/dom/js/jslong.h
src/dom/js/jsmath.c
src/dom/js/jsmath.h
src/dom/js/jsnum.c
src/dom/js/jsnum.h
src/dom/js/jsobj.c
src/dom/js/jsobj.h
src/dom/js/jsopcode.c
src/dom/js/jsopcode.h
src/dom/js/jsopcode.tbl
src/dom/js/jsosdep.h
src/dom/js/jsotypes.h
src/dom/js/jsparse.c
src/dom/js/jsparse.h
src/dom/js/jsprf.c
src/dom/js/jsprf.h
src/dom/js/jsprvtd.h
src/dom/js/jspubtd.h
src/dom/js/jsregexp.c
src/dom/js/jsregexp.h
src/dom/js/jsscan.c
src/dom/js/jsscan.h
src/dom/js/jsscope.c
src/dom/js/jsscope.h
src/dom/js/jsscript.c
src/dom/js/jsscript.h
src/dom/js/jsstddef.h
src/dom/js/jsstr.c
src/dom/js/jsstr.h
src/dom/js/jstypes.h
src/dom/js/jsutil.c
src/dom/js/jsutil.h
src/dom/js/jsxdrapi.c
src/dom/js/jsxml.c [new file with mode: 0644]
src/dom/js/jsxml.h [new file with mode: 0644]
src/dom/js/prmjtime.c
src/dom/js/prmjtime.h

index 33b6aed9eb794c8ee5c51a754d8c103ecf34e93a..b47437265f13e9ff80bd76af91f28c4c15fd4985 100644 (file)
@@ -203,6 +203,7 @@ js/jsscript.o \
 js/jsstr.o \
 js/jsutil.o \
 js/jsxdrapi.o \
+js/jsxml.o \
 js/prmjtime.o \
 js/fdlibm/e_acos.o \
 js/fdlibm/e_acosh.o \
diff --git a/src/dom/js/README.ink b/src/dom/js/README.ink
new file mode 100644 (file)
index 0000000..bbb5327
--- /dev/null
@@ -0,0 +1,10 @@
+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/.cvsignore b/src/dom/js/fdlibm/.cvsignore
deleted file mode 100644 (file)
index bb5cc66..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-*.pdb
-*.ncb
-*.opt
-*.plg
-Debug
-Release
-Makefile
diff --git a/src/dom/js/fdlibm/Makefile.in b/src/dom/js/fdlibm/Makefile.in
deleted file mode 100644 (file)
index fdec7b7..0000000
+++ /dev/null
@@ -1,127 +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
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either of the GNU General Public License Version 2 or later (the "GPL"),
-# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-DEPTH          = ../../..
-topsrcdir      = @top_srcdir@
-srcdir         = @srcdir@
-VPATH          = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE         = js
-LIBRARY_NAME   = fdm
-
-CSRCS          = \
-               e_acos.c \
-               e_asin.c \
-               e_atan2.c \
-               e_exp.c \
-               e_fmod.c \
-               e_log.c \
-               e_pow.c \
-               e_rem_pio2.c \
-               s_scalbn.c \
-               e_sqrt.c \
-               k_cos.c \
-               k_sin.c \
-               k_rem_pio2.c \
-               k_tan.c \
-               s_atan.c \
-               s_ceil.c \
-               s_copysign.c \
-               s_cos.c \
-               s_fabs.c \
-               s_finite.c \
-               s_floor.c \
-               s_isnan.c \
-               s_lib_version.c \
-               s_sin.c \
-               s_tan.c \
-               w_acos.c \
-               w_asin.c \
-               w_atan2.c \
-               w_exp.c \
-               w_fmod.c \
-               w_log.c \
-               w_pow.c \
-               w_sqrt.c \
-               $(NULL)
-
-EXPORTS                = fdlibm.h
-
-# we need to force a static lib for the linking that js/src/Makefile.in wants
-# to do, and we don't really need a shared library ever, so:
-FORCE_STATIC_LIB = 1
-FORCE_USE_PIC = 1
-
-include $(topsrcdir)/config/rules.mk
-
-#
-# Default IEEE libm
-#
-CFLAGS         += -D_IEEE_LIBM
-
-ifeq ($(OS_ARCH),Linux)
-LDFLAGS                += -ldl
-endif
-
-ifeq ($(OS_ARCH),OSF1)
-LDFLAGS                += -lc_r
-endif
-
-ifeq ($(OS_ARCH),SunOS)
-LDFLAGS                += -lposix4 -ldl -lnsl -lsocket
-ifeq ($(CPU_ARCH),sparc)
-
-ifndef JS_NO_ULTRA
-ULTRA_OPTIONS  := -xarch=v8plus,-DULTRA_SPARC
-ULTRA_OPTIONSCC        := -DULTRA_SPARC
-else
-ULTRA_OPTIONS  := -xarch=v8
-ULTRA_OPTIONSCC        :=
-endif
-
-ifeq ($(shell uname -m),sun4u)
-ASFLAGS                += -Wa,$(ULTRA_OPTIONS),-P,-L,-D_ASM,-D__STDC__=0 $(ULTRA_OPTIONSCC)
-else
-ASFLAGS                += -Wa,-xarch=v8,-P,-L,-D_ASM,-D__STDC__=0
-endif
-
-endif
-endif
-
diff --git a/src/dom/js/fdlibm/Makefile.ref b/src/dom/js/fdlibm/Makefile.ref
deleted file mode 100644 (file)
index de37802..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-# -*- Mode: makefile -*-
-#
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and 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 *****
-
-#
-#  @(#)Makefile 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.
-#  ====================================================
-# 
-# 
-
-#
-# There are two options in making libm at fdlibm compile time:
-#       _IEEE_LIBM      --- IEEE libm; smaller, and somewhat faster
-#       _MULTI_LIBM     --- Support multi-standard at runtime by 
-#                           imposing wrapper functions defined in 
-#                           fdlibm.h:
-#                               _IEEE_MODE      -- IEEE
-#                               _XOPEN_MODE     -- X/OPEN
-#                               _POSIX_MODE     -- POSIX/ANSI
-#                               _SVID3_MODE     -- SVID
-#
-# Here is how to set up CFLAGS to create the desired libm at 
-# compile time:
-#
-#       CFLAGS = -D_IEEE_LIBM           ... IEEE libm (recommended)
-#       CFLAGS = -D_SVID3_MODE  ... Multi-standard supported
-#                                           libm with SVID as the 
-#                                           default standard
-#       CFLAGS = -D_XOPEN_MODE  ... Multi-standard supported
-#                                           libm with XOPEN as the 
-#                                           default standard
-#       CFLAGS = -D_POSIX_MODE  ... Multi-standard supported
-#                                           libm with POSIX as the 
-#                                           default standard
-#       CFLAGS =                        ... Multi-standard supported
-#                                           libm with IEEE as the 
-#                                           default standard
-# 
-# NOTE: if scalb's second arguement is an int, then one must
-# define _SCALB_INT in CFLAGS. The default prototype of scalb
-# is double scalb(double, double)
-#
-
-DEPTH           = ..
-
-include $(DEPTH)/config.mk
-
-#
-# Default IEEE libm
-#
-CFLAGS          += -DXP_UNIX $(OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) \
-                 -DJSFILE $(XCFLAGS) -D_IEEE_LIBM
-
-# Need for jstypes.h and friends
-INCLUDES += -I..
-INCLUDES += -I../$(OBJDIR)
-
-#CC = cc
-
-INCFILES = fdlibm.h
-.INIT: $(INCFILES)
-.KEEP_STATE:
-FDLIBM_CFILES =         \
-       k_standard.c k_rem_pio2.c \
-       k_cos.c k_sin.c k_tan.c \
-       e_acos.c e_acosh.c e_asin.c e_atan2.c \
-       e_atanh.c e_cosh.c e_exp.c e_fmod.c \
-       e_gamma.c e_gamma_r.c e_hypot.c e_j0.c \
-       e_j1.c e_jn.c e_lgamma.c e_lgamma_r.c \
-       e_log.c e_log10.c e_pow.c e_rem_pio2.c e_remainder.c \
-       e_scalb.c e_sinh.c e_sqrt.c \
-       w_acos.c w_acosh.c w_asin.c w_atan2.c \
-       w_atanh.c w_cosh.c w_exp.c w_fmod.c \
-       w_gamma.c w_gamma_r.c w_hypot.c w_j0.c \
-       w_j1.c w_jn.c w_lgamma.c w_lgamma_r.c \
-       w_log.c w_log10.c w_pow.c w_remainder.c \
-       w_scalb.c w_sinh.c w_sqrt.c \
-       s_asinh.c s_atan.c s_cbrt.c s_ceil.c s_copysign.c \
-       s_cos.c s_erf.c s_expm1.c s_fabs.c s_finite.c s_floor.c \
-       s_frexp.c s_ilogb.c s_isnan.c s_ldexp.c s_lib_version.c \
-       s_log1p.c s_logb.c s_matherr.c s_modf.c s_nextafter.c \
-       s_rint.c s_scalbn.c s_signgam.c s_significand.c s_sin.c \
-       s_tan.c s_tanh.c
-
-ifdef USE_MSVC
-FDLIBM_OBJS = $(addprefix $(OBJDIR)/, $(FDLIBM_CFILES:.c=.obj))
-else
-FDLIBM_OBJS = $(addprefix $(OBJDIR)/, $(FDLIBM_CFILES:.c=.o))
-endif
-
-ifdef USE_MSVC
-LIBRARY = $(OBJDIR)/fdlibm.lib
-else
-LIBRARY = $(OBJDIR)/libfdm.a
-endif
-
-define MAKE_OBJDIR
-if test ! -d $(@D); then rm -rf $(@D); mkdir -p $(@D); fi
-endef
-
-all: $(LIBRARY) 
-
-export:
-
-$(OBJDIR)/%: %.c
-       @$(MAKE_OBJDIR)
-       $(CC) -o $@ $(CFLAGS) $*.c $(LDFLAGS)
-
-$(OBJDIR)/%.o: %.c
-       @$(MAKE_OBJDIR)
-       $(CC) -o $@ -c $(CFLAGS) $*.c
-
-$(OBJDIR)/%.o: %.s
-       @$(MAKE_OBJDIR)
-       $(AS) -o $@ $(ASFLAGS) $*.s
-
-# windows only
-$(OBJDIR)/%.obj: %.c
-       @$(MAKE_OBJDIR)
-       $(CC) -Fo$(OBJDIR)/ -c $(CFLAGS) $*.c
-
-ifeq ($(OS_ARCH),OS2)
-$(LIBRARY): $(FDLIBM_OBJS)
-       $(AR) $@ $? $(AR_OS2_SUFFIX)
-       $(RANLIB) $@
-else
-ifdef USE_MSVC
-$(LIBRARY): $(FDLIBM_OBJS)
-       lib.exe /out:"$@" $?
-else
-$(LIBRARY): $(FDLIBM_OBJS)
-       $(AR) rv $@ $?
-       $(RANLIB) $@
-endif
-endif
-
-libfdm.a : $(FDLIBM_OBJS) 
-       $(AR) cru $(OBJDIR)/libfdm.a $(FDLIBM_OBJS)
-       $(RANLIB) $(OBJDIR)/libfdm.a
-
-clean:
-       rm -rf $(FDLIBM_OBJS)
-
-clobber:
-       rm -rf $(FDLIBM_OBJS) $(LIBRARY) $(DEPENDENCIES)
-
-SUFFIXES: .i
-%.i: %.c
-       $(CC) -C -E $(CFLAGS) $< > $*.i
index 6f9423551ef8a832c8f5caa4fd568f21e7abf964..c9d26187510bade8e30d993cd1c31dc9e16e5c8e 100644 (file)
@@ -126,7 +126,8 @@ pio2_3t =  8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
 #endif
 {
         fd_twoints u, ux, uz;
-       double z,w,t,r,fn;
+        double z = 0;
+       double w,t,r,fn;
        double tx[3];
        int e0,i,j,nx,n,ix,hx;
 
index 8e25214f08413a8aecb7676668a08a09634921e1..e623be56e450f0a356b4f044e4f1add14a11a2ca 100644 (file)
 #define __LITTLE_ENDIAN
 #endif
 
-#if defined(linux) && (defined(__i386__) || defined(__x86_64__))
+#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 __NEWVALID      /* special setup for Sun test regime */
+#ifdef SOLARIS /* special setup for Sun test regime */
 #if defined(i386) || defined(i486) || \
        defined(intel) || defined(x86) || defined(i86pc)
 #define __LITTLE_ENDIAN
diff --git a/src/dom/js/fdlibm/fdlibm.mak b/src/dom/js/fdlibm/fdlibm.mak
deleted file mode 100644 (file)
index 436c1c4..0000000
+++ /dev/null
@@ -1,1453 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
-\r
-!IF "$(CFG)" == ""\r
-CFG=fdlibm - Win32 Debug\r
-!MESSAGE No configuration specified.  Defaulting to fdlibm - Win32 Debug.\r
-!ENDIF \r
-\r
-!IF "$(CFG)" != "fdlibm - Win32 Release" && "$(CFG)" != "fdlibm - Win32 Debug"\r
-!MESSAGE Invalid configuration "$(CFG)" specified.\r
-!MESSAGE You can specify a configuration when running NMAKE on this makefile\r
-!MESSAGE by defining the macro CFG on the command line.  For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "fdlibm.mak" CFG="fdlibm - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "fdlibm - Win32 Release" (based on "Win32 (x86) Static Library")\r
-!MESSAGE "fdlibm - Win32 Debug" (based on "Win32 (x86) Static Library")\r
-!MESSAGE \r
-!ERROR An invalid configuration is specified.\r
-!ENDIF \r
-\r
-!IF "$(OS)" == "Windows_NT"\r
-NULL=\r
-!ELSE \r
-NULL=nul\r
-!ENDIF \r
-################################################################################\r
-# Begin Project\r
-CPP=cl.exe\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "fdlibm__"\r
-# PROP BASE Intermediate_Dir "fdlibm__"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir "fdlibm__"\r
-# PROP Intermediate_Dir "fdlibm__"\r
-# PROP Target_Dir ""\r
-OUTDIR=.\fdlibm__\r
-INTDIR=.\fdlibm__\r
-\r
-ALL : "$(OUTDIR)\fdlibm.lib"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\e_acos.obj"\r
-       -@erase "$(INTDIR)\e_acosh.obj"\r
-       -@erase "$(INTDIR)\e_asin.obj"\r
-       -@erase "$(INTDIR)\e_atan2.obj"\r
-       -@erase "$(INTDIR)\e_atanh.obj"\r
-       -@erase "$(INTDIR)\e_cosh.obj"\r
-       -@erase "$(INTDIR)\e_exp.obj"\r
-       -@erase "$(INTDIR)\e_fmod.obj"\r
-       -@erase "$(INTDIR)\e_gamma.obj"\r
-       -@erase "$(INTDIR)\e_gamma_r.obj"\r
-       -@erase "$(INTDIR)\e_hypot.obj"\r
-       -@erase "$(INTDIR)\e_j0.obj"\r
-       -@erase "$(INTDIR)\e_j1.obj"\r
-       -@erase "$(INTDIR)\e_jn.obj"\r
-       -@erase "$(INTDIR)\e_lgamma.obj"\r
-       -@erase "$(INTDIR)\e_lgamma_r.obj"\r
-       -@erase "$(INTDIR)\e_log.obj"\r
-       -@erase "$(INTDIR)\e_log10.obj"\r
-       -@erase "$(INTDIR)\e_pow.obj"\r
-       -@erase "$(INTDIR)\e_rem_pio2.obj"\r
-       -@erase "$(INTDIR)\e_remainder.obj"\r
-       -@erase "$(INTDIR)\e_scalb.obj"\r
-       -@erase "$(INTDIR)\e_sinh.obj"\r
-       -@erase "$(INTDIR)\e_sqrt.obj"\r
-       -@erase "$(INTDIR)\k_cos.obj"\r
-       -@erase "$(INTDIR)\k_rem_pio2.obj"\r
-       -@erase "$(INTDIR)\k_sin.obj"\r
-       -@erase "$(INTDIR)\k_standard.obj"\r
-       -@erase "$(INTDIR)\k_tan.obj"\r
-       -@erase "$(INTDIR)\s_asinh.obj"\r
-       -@erase "$(INTDIR)\s_atan.obj"\r
-       -@erase "$(INTDIR)\s_cbrt.obj"\r
-       -@erase "$(INTDIR)\s_ceil.obj"\r
-       -@erase "$(INTDIR)\s_copysign.obj"\r
-       -@erase "$(INTDIR)\s_cos.obj"\r
-       -@erase "$(INTDIR)\s_erf.obj"\r
-       -@erase "$(INTDIR)\s_expm1.obj"\r
-       -@erase "$(INTDIR)\s_fabs.obj"\r
-       -@erase "$(INTDIR)\s_finite.obj"\r
-       -@erase "$(INTDIR)\s_floor.obj"\r
-       -@erase "$(INTDIR)\s_frexp.obj"\r
-       -@erase "$(INTDIR)\s_ilogb.obj"\r
-       -@erase "$(INTDIR)\s_isnan.obj"\r
-       -@erase "$(INTDIR)\s_ldexp.obj"\r
-       -@erase "$(INTDIR)\s_lib_version.obj"\r
-       -@erase "$(INTDIR)\s_log1p.obj"\r
-       -@erase "$(INTDIR)\s_logb.obj"\r
-       -@erase "$(INTDIR)\s_matherr.obj"\r
-       -@erase "$(INTDIR)\s_modf.obj"\r
-       -@erase "$(INTDIR)\s_nextafter.obj"\r
-       -@erase "$(INTDIR)\s_rint.obj"\r
-       -@erase "$(INTDIR)\s_scalbn.obj"\r
-       -@erase "$(INTDIR)\s_signgam.obj"\r
-       -@erase "$(INTDIR)\s_significand.obj"\r
-       -@erase "$(INTDIR)\s_sin.obj"\r
-       -@erase "$(INTDIR)\s_tan.obj"\r
-       -@erase "$(INTDIR)\s_tanh.obj"\r
-       -@erase "$(INTDIR)\w_acos.obj"\r
-       -@erase "$(INTDIR)\w_acosh.obj"\r
-       -@erase "$(INTDIR)\w_asin.obj"\r
-       -@erase "$(INTDIR)\w_atan2.obj"\r
-       -@erase "$(INTDIR)\w_atanh.obj"\r
-       -@erase "$(INTDIR)\w_cosh.obj"\r
-       -@erase "$(INTDIR)\w_exp.obj"\r
-       -@erase "$(INTDIR)\w_fmod.obj"\r
-       -@erase "$(INTDIR)\w_gamma.obj"\r
-       -@erase "$(INTDIR)\w_gamma_r.obj"\r
-       -@erase "$(INTDIR)\w_hypot.obj"\r
-       -@erase "$(INTDIR)\w_j0.obj"\r
-       -@erase "$(INTDIR)\w_j1.obj"\r
-       -@erase "$(INTDIR)\w_jn.obj"\r
-       -@erase "$(INTDIR)\w_lgamma.obj"\r
-       -@erase "$(INTDIR)\w_lgamma_r.obj"\r
-       -@erase "$(INTDIR)\w_log.obj"\r
-       -@erase "$(INTDIR)\w_log10.obj"\r
-       -@erase "$(INTDIR)\w_pow.obj"\r
-       -@erase "$(INTDIR)\w_remainder.obj"\r
-       -@erase "$(INTDIR)\w_scalb.obj"\r
-       -@erase "$(INTDIR)\w_sinh.obj"\r
-       -@erase "$(INTDIR)\w_sqrt.obj"\r
-       -@erase "$(OUTDIR)\fdlibm.lib"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c\r
-# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c\r
-CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\\r
- /Fp"$(INTDIR)/fdlibm.pch" /YX /Fo"$(INTDIR)/" /c \r
-CPP_OBJS=.\fdlibm__/\r
-CPP_SBRS=.\.\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/fdlibm.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LIB32=link.exe -lib\r
-# ADD BASE LIB32 /nologo\r
-# ADD LIB32 /nologo\r
-LIB32_FLAGS=/nologo /out:"$(OUTDIR)/fdlibm.lib" \r
-LIB32_OBJS= \\r
-       "$(INTDIR)\e_acos.obj" \\r
-       "$(INTDIR)\e_acosh.obj" \\r
-       "$(INTDIR)\e_asin.obj" \\r
-       "$(INTDIR)\e_atan2.obj" \\r
-       "$(INTDIR)\e_atanh.obj" \\r
-       "$(INTDIR)\e_cosh.obj" \\r
-       "$(INTDIR)\e_exp.obj" \\r
-       "$(INTDIR)\e_fmod.obj" \\r
-       "$(INTDIR)\e_gamma.obj" \\r
-       "$(INTDIR)\e_gamma_r.obj" \\r
-       "$(INTDIR)\e_hypot.obj" \\r
-       "$(INTDIR)\e_j0.obj" \\r
-       "$(INTDIR)\e_j1.obj" \\r
-       "$(INTDIR)\e_jn.obj" \\r
-       "$(INTDIR)\e_lgamma.obj" \\r
-       "$(INTDIR)\e_lgamma_r.obj" \\r
-       "$(INTDIR)\e_log.obj" \\r
-       "$(INTDIR)\e_log10.obj" \\r
-       "$(INTDIR)\e_pow.obj" \\r
-       "$(INTDIR)\e_rem_pio2.obj" \\r
-       "$(INTDIR)\e_remainder.obj" \\r
-       "$(INTDIR)\e_scalb.obj" \\r
-       "$(INTDIR)\e_sinh.obj" \\r
-       "$(INTDIR)\e_sqrt.obj" \\r
-       "$(INTDIR)\k_cos.obj" \\r
-       "$(INTDIR)\k_rem_pio2.obj" \\r
-       "$(INTDIR)\k_sin.obj" \\r
-       "$(INTDIR)\k_standard.obj" \\r
-       "$(INTDIR)\k_tan.obj" \\r
-       "$(INTDIR)\s_asinh.obj" \\r
-       "$(INTDIR)\s_atan.obj" \\r
-       "$(INTDIR)\s_cbrt.obj" \\r
-       "$(INTDIR)\s_ceil.obj" \\r
-       "$(INTDIR)\s_copysign.obj" \\r
-       "$(INTDIR)\s_cos.obj" \\r
-       "$(INTDIR)\s_erf.obj" \\r
-       "$(INTDIR)\s_expm1.obj" \\r
-       "$(INTDIR)\s_fabs.obj" \\r
-       "$(INTDIR)\s_finite.obj" \\r
-       "$(INTDIR)\s_floor.obj" \\r
-       "$(INTDIR)\s_frexp.obj" \\r
-       "$(INTDIR)\s_ilogb.obj" \\r
-       "$(INTDIR)\s_isnan.obj" \\r
-       "$(INTDIR)\s_ldexp.obj" \\r
-       "$(INTDIR)\s_lib_version.obj" \\r
-       "$(INTDIR)\s_log1p.obj" \\r
-       "$(INTDIR)\s_logb.obj" \\r
-       "$(INTDIR)\s_matherr.obj" \\r
-       "$(INTDIR)\s_modf.obj" \\r
-       "$(INTDIR)\s_nextafter.obj" \\r
-       "$(INTDIR)\s_rint.obj" \\r
-       "$(INTDIR)\s_scalbn.obj" \\r
-       "$(INTDIR)\s_signgam.obj" \\r
-       "$(INTDIR)\s_significand.obj" \\r
-       "$(INTDIR)\s_sin.obj" \\r
-       "$(INTDIR)\s_tan.obj" \\r
-       "$(INTDIR)\s_tanh.obj" \\r
-       "$(INTDIR)\w_acos.obj" \\r
-       "$(INTDIR)\w_acosh.obj" \\r
-       "$(INTDIR)\w_asin.obj" \\r
-       "$(INTDIR)\w_atan2.obj" \\r
-       "$(INTDIR)\w_atanh.obj" \\r
-       "$(INTDIR)\w_cosh.obj" \\r
-       "$(INTDIR)\w_exp.obj" \\r
-       "$(INTDIR)\w_fmod.obj" \\r
-       "$(INTDIR)\w_gamma.obj" \\r
-       "$(INTDIR)\w_gamma_r.obj" \\r
-       "$(INTDIR)\w_hypot.obj" \\r
-       "$(INTDIR)\w_j0.obj" \\r
-       "$(INTDIR)\w_j1.obj" \\r
-       "$(INTDIR)\w_jn.obj" \\r
-       "$(INTDIR)\w_lgamma.obj" \\r
-       "$(INTDIR)\w_lgamma_r.obj" \\r
-       "$(INTDIR)\w_log.obj" \\r
-       "$(INTDIR)\w_log10.obj" \\r
-       "$(INTDIR)\w_pow.obj" \\r
-       "$(INTDIR)\w_remainder.obj" \\r
-       "$(INTDIR)\w_scalb.obj" \\r
-       "$(INTDIR)\w_sinh.obj" \\r
-       "$(INTDIR)\w_sqrt.obj"\r
-\r
-"$(OUTDIR)\fdlibm.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)\r
-    $(LIB32) @<<\r
-  $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)\r
-<<\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "fdlibm_0"\r
-# PROP BASE Intermediate_Dir "fdlibm_0"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir "fdlibm_0"\r
-# PROP Intermediate_Dir "fdlibm_0"\r
-# PROP Target_Dir ""\r
-OUTDIR=.\fdlibm_0\r
-INTDIR=.\fdlibm_0\r
-\r
-ALL : "$(OUTDIR)\fdlibm.lib"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\e_acos.obj"\r
-       -@erase "$(INTDIR)\e_acosh.obj"\r
-       -@erase "$(INTDIR)\e_asin.obj"\r
-       -@erase "$(INTDIR)\e_atan2.obj"\r
-       -@erase "$(INTDIR)\e_atanh.obj"\r
-       -@erase "$(INTDIR)\e_cosh.obj"\r
-       -@erase "$(INTDIR)\e_exp.obj"\r
-       -@erase "$(INTDIR)\e_fmod.obj"\r
-       -@erase "$(INTDIR)\e_gamma.obj"\r
-       -@erase "$(INTDIR)\e_gamma_r.obj"\r
-       -@erase "$(INTDIR)\e_hypot.obj"\r
-       -@erase "$(INTDIR)\e_j0.obj"\r
-       -@erase "$(INTDIR)\e_j1.obj"\r
-       -@erase "$(INTDIR)\e_jn.obj"\r
-       -@erase "$(INTDIR)\e_lgamma.obj"\r
-       -@erase "$(INTDIR)\e_lgamma_r.obj"\r
-       -@erase "$(INTDIR)\e_log.obj"\r
-       -@erase "$(INTDIR)\e_log10.obj"\r
-       -@erase "$(INTDIR)\e_pow.obj"\r
-       -@erase "$(INTDIR)\e_rem_pio2.obj"\r
-       -@erase "$(INTDIR)\e_remainder.obj"\r
-       -@erase "$(INTDIR)\e_scalb.obj"\r
-       -@erase "$(INTDIR)\e_sinh.obj"\r
-       -@erase "$(INTDIR)\e_sqrt.obj"\r
-       -@erase "$(INTDIR)\k_cos.obj"\r
-       -@erase "$(INTDIR)\k_rem_pio2.obj"\r
-       -@erase "$(INTDIR)\k_sin.obj"\r
-       -@erase "$(INTDIR)\k_standard.obj"\r
-       -@erase "$(INTDIR)\k_tan.obj"\r
-       -@erase "$(INTDIR)\s_asinh.obj"\r
-       -@erase "$(INTDIR)\s_atan.obj"\r
-       -@erase "$(INTDIR)\s_cbrt.obj"\r
-       -@erase "$(INTDIR)\s_ceil.obj"\r
-       -@erase "$(INTDIR)\s_copysign.obj"\r
-       -@erase "$(INTDIR)\s_cos.obj"\r
-       -@erase "$(INTDIR)\s_erf.obj"\r
-       -@erase "$(INTDIR)\s_expm1.obj"\r
-       -@erase "$(INTDIR)\s_fabs.obj"\r
-       -@erase "$(INTDIR)\s_finite.obj"\r
-       -@erase "$(INTDIR)\s_floor.obj"\r
-       -@erase "$(INTDIR)\s_frexp.obj"\r
-       -@erase "$(INTDIR)\s_ilogb.obj"\r
-       -@erase "$(INTDIR)\s_isnan.obj"\r
-       -@erase "$(INTDIR)\s_ldexp.obj"\r
-       -@erase "$(INTDIR)\s_lib_version.obj"\r
-       -@erase "$(INTDIR)\s_log1p.obj"\r
-       -@erase "$(INTDIR)\s_logb.obj"\r
-       -@erase "$(INTDIR)\s_matherr.obj"\r
-       -@erase "$(INTDIR)\s_modf.obj"\r
-       -@erase "$(INTDIR)\s_nextafter.obj"\r
-       -@erase "$(INTDIR)\s_rint.obj"\r
-       -@erase "$(INTDIR)\s_scalbn.obj"\r
-       -@erase "$(INTDIR)\s_signgam.obj"\r
-       -@erase "$(INTDIR)\s_significand.obj"\r
-       -@erase "$(INTDIR)\s_sin.obj"\r
-       -@erase "$(INTDIR)\s_tan.obj"\r
-       -@erase "$(INTDIR)\s_tanh.obj"\r
-       -@erase "$(INTDIR)\w_acos.obj"\r
-       -@erase "$(INTDIR)\w_acosh.obj"\r
-       -@erase "$(INTDIR)\w_asin.obj"\r
-       -@erase "$(INTDIR)\w_atan2.obj"\r
-       -@erase "$(INTDIR)\w_atanh.obj"\r
-       -@erase "$(INTDIR)\w_cosh.obj"\r
-       -@erase "$(INTDIR)\w_exp.obj"\r
-       -@erase "$(INTDIR)\w_fmod.obj"\r
-       -@erase "$(INTDIR)\w_gamma.obj"\r
-       -@erase "$(INTDIR)\w_gamma_r.obj"\r
-       -@erase "$(INTDIR)\w_hypot.obj"\r
-       -@erase "$(INTDIR)\w_j0.obj"\r
-       -@erase "$(INTDIR)\w_j1.obj"\r
-       -@erase "$(INTDIR)\w_jn.obj"\r
-       -@erase "$(INTDIR)\w_lgamma.obj"\r
-       -@erase "$(INTDIR)\w_lgamma_r.obj"\r
-       -@erase "$(INTDIR)\w_log.obj"\r
-       -@erase "$(INTDIR)\w_log10.obj"\r
-       -@erase "$(INTDIR)\w_pow.obj"\r
-       -@erase "$(INTDIR)\w_remainder.obj"\r
-       -@erase "$(INTDIR)\w_scalb.obj"\r
-       -@erase "$(INTDIR)\w_sinh.obj"\r
-       -@erase "$(INTDIR)\w_sqrt.obj"\r
-       -@erase "$(OUTDIR)\fdlibm.lib"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c\r
-# ADD CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c\r
-CPP_PROJ=/nologo /MLd /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\\r
- /Fp"$(INTDIR)/fdlibm.pch" /YX /Fo"$(INTDIR)/" /c \r
-CPP_OBJS=.\fdlibm_0/\r
-CPP_SBRS=.\.\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/fdlibm.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LIB32=link.exe -lib\r
-# ADD BASE LIB32 /nologo\r
-# ADD LIB32 /nologo\r
-LIB32_FLAGS=/nologo /out:"$(OUTDIR)/fdlibm.lib" \r
-LIB32_OBJS= \\r
-       "$(INTDIR)\e_acos.obj" \\r
-       "$(INTDIR)\e_acosh.obj" \\r
-       "$(INTDIR)\e_asin.obj" \\r
-       "$(INTDIR)\e_atan2.obj" \\r
-       "$(INTDIR)\e_atanh.obj" \\r
-       "$(INTDIR)\e_cosh.obj" \\r
-       "$(INTDIR)\e_exp.obj" \\r
-       "$(INTDIR)\e_fmod.obj" \\r
-       "$(INTDIR)\e_gamma.obj" \\r
-       "$(INTDIR)\e_gamma_r.obj" \\r
-       "$(INTDIR)\e_hypot.obj" \\r
-       "$(INTDIR)\e_j0.obj" \\r
-       "$(INTDIR)\e_j1.obj" \\r
-       "$(INTDIR)\e_jn.obj" \\r
-       "$(INTDIR)\e_lgamma.obj" \\r
-       "$(INTDIR)\e_lgamma_r.obj" \\r
-       "$(INTDIR)\e_log.obj" \\r
-       "$(INTDIR)\e_log10.obj" \\r
-       "$(INTDIR)\e_pow.obj" \\r
-       "$(INTDIR)\e_rem_pio2.obj" \\r
-       "$(INTDIR)\e_remainder.obj" \\r
-       "$(INTDIR)\e_scalb.obj" \\r
-       "$(INTDIR)\e_sinh.obj" \\r
-       "$(INTDIR)\e_sqrt.obj" \\r
-       "$(INTDIR)\k_cos.obj" \\r
-       "$(INTDIR)\k_rem_pio2.obj" \\r
-       "$(INTDIR)\k_sin.obj" \\r
-       "$(INTDIR)\k_standard.obj" \\r
-       "$(INTDIR)\k_tan.obj" \\r
-       "$(INTDIR)\s_asinh.obj" \\r
-       "$(INTDIR)\s_atan.obj" \\r
-       "$(INTDIR)\s_cbrt.obj" \\r
-       "$(INTDIR)\s_ceil.obj" \\r
-       "$(INTDIR)\s_copysign.obj" \\r
-       "$(INTDIR)\s_cos.obj" \\r
-       "$(INTDIR)\s_erf.obj" \\r
-       "$(INTDIR)\s_expm1.obj" \\r
-       "$(INTDIR)\s_fabs.obj" \\r
-       "$(INTDIR)\s_finite.obj" \\r
-       "$(INTDIR)\s_floor.obj" \\r
-       "$(INTDIR)\s_frexp.obj" \\r
-       "$(INTDIR)\s_ilogb.obj" \\r
-       "$(INTDIR)\s_isnan.obj" \\r
-       "$(INTDIR)\s_ldexp.obj" \\r
-       "$(INTDIR)\s_lib_version.obj" \\r
-       "$(INTDIR)\s_log1p.obj" \\r
-       "$(INTDIR)\s_logb.obj" \\r
-       "$(INTDIR)\s_matherr.obj" \\r
-       "$(INTDIR)\s_modf.obj" \\r
-       "$(INTDIR)\s_nextafter.obj" \\r
-       "$(INTDIR)\s_rint.obj" \\r
-       "$(INTDIR)\s_scalbn.obj" \\r
-       "$(INTDIR)\s_signgam.obj" \\r
-       "$(INTDIR)\s_significand.obj" \\r
-       "$(INTDIR)\s_sin.obj" \\r
-       "$(INTDIR)\s_tan.obj" \\r
-       "$(INTDIR)\s_tanh.obj" \\r
-       "$(INTDIR)\w_acos.obj" \\r
-       "$(INTDIR)\w_acosh.obj" \\r
-       "$(INTDIR)\w_asin.obj" \\r
-       "$(INTDIR)\w_atan2.obj" \\r
-       "$(INTDIR)\w_atanh.obj" \\r
-       "$(INTDIR)\w_cosh.obj" \\r
-       "$(INTDIR)\w_exp.obj" \\r
-       "$(INTDIR)\w_fmod.obj" \\r
-       "$(INTDIR)\w_gamma.obj" \\r
-       "$(INTDIR)\w_gamma_r.obj" \\r
-       "$(INTDIR)\w_hypot.obj" \\r
-       "$(INTDIR)\w_j0.obj" \\r
-       "$(INTDIR)\w_j1.obj" \\r
-       "$(INTDIR)\w_jn.obj" \\r
-       "$(INTDIR)\w_lgamma.obj" \\r
-       "$(INTDIR)\w_lgamma_r.obj" \\r
-       "$(INTDIR)\w_log.obj" \\r
-       "$(INTDIR)\w_log10.obj" \\r
-       "$(INTDIR)\w_pow.obj" \\r
-       "$(INTDIR)\w_remainder.obj" \\r
-       "$(INTDIR)\w_scalb.obj" \\r
-       "$(INTDIR)\w_sinh.obj" \\r
-       "$(INTDIR)\w_sqrt.obj"\r
-\r
-"$(OUTDIR)\fdlibm.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)\r
-    $(LIB32) @<<\r
-  $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)\r
-<<\r
-\r
-!ENDIF \r
-\r
-.c{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.c{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-################################################################################\r
-# Begin Target\r
-\r
-# Name "fdlibm - Win32 Release"\r
-# Name "fdlibm - Win32 Debug"\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-!ENDIF \r
-\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_sqrt.c\r
-DEP_CPP_W_SQR=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_sqrt.obj" : $(SOURCE) $(DEP_CPP_W_SQR) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_acosh.c\r
-DEP_CPP_E_ACO=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_acosh.obj" : $(SOURCE) $(DEP_CPP_E_ACO) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_asin.c\r
-DEP_CPP_E_ASI=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_asin.obj" : $(SOURCE) $(DEP_CPP_E_ASI) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_atan2.c\r
-DEP_CPP_E_ATA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_atan2.obj" : $(SOURCE) $(DEP_CPP_E_ATA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_atanh.c\r
-DEP_CPP_E_ATAN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_atanh.obj" : $(SOURCE) $(DEP_CPP_E_ATAN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_cosh.c\r
-DEP_CPP_E_COS=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_cosh.obj" : $(SOURCE) $(DEP_CPP_E_COS) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_exp.c\r
-DEP_CPP_E_EXP=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_exp.obj" : $(SOURCE) $(DEP_CPP_E_EXP) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_fmod.c\r
-DEP_CPP_E_FMO=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_fmod.obj" : $(SOURCE) $(DEP_CPP_E_FMO) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_gamma.c\r
-DEP_CPP_E_GAM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_gamma.obj" : $(SOURCE) $(DEP_CPP_E_GAM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_gamma_r.c\r
-DEP_CPP_E_GAMM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_gamma_r.obj" : $(SOURCE) $(DEP_CPP_E_GAMM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_hypot.c\r
-DEP_CPP_E_HYP=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_hypot.obj" : $(SOURCE) $(DEP_CPP_E_HYP) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_j0.c\r
-DEP_CPP_E_J0_=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_j0.obj" : $(SOURCE) $(DEP_CPP_E_J0_) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_j1.c\r
-DEP_CPP_E_J1_=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_j1.obj" : $(SOURCE) $(DEP_CPP_E_J1_) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_jn.c\r
-DEP_CPP_E_JN_=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_jn.obj" : $(SOURCE) $(DEP_CPP_E_JN_) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_lgamma.c\r
-DEP_CPP_E_LGA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_lgamma.obj" : $(SOURCE) $(DEP_CPP_E_LGA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_lgamma_r.c\r
-DEP_CPP_E_LGAM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_lgamma_r.obj" : $(SOURCE) $(DEP_CPP_E_LGAM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_log.c\r
-DEP_CPP_E_LOG=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_log.obj" : $(SOURCE) $(DEP_CPP_E_LOG) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_log10.c\r
-DEP_CPP_E_LOG1=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_log10.obj" : $(SOURCE) $(DEP_CPP_E_LOG1) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_pow.c\r
-DEP_CPP_E_POW=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_pow.obj" : $(SOURCE) $(DEP_CPP_E_POW) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_rem_pio2.c\r
-DEP_CPP_E_REM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_rem_pio2.obj" : $(SOURCE) $(DEP_CPP_E_REM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_remainder.c\r
-DEP_CPP_E_REMA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_remainder.obj" : $(SOURCE) $(DEP_CPP_E_REMA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_scalb.c\r
-DEP_CPP_E_SCA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_scalb.obj" : $(SOURCE) $(DEP_CPP_E_SCA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_sinh.c\r
-DEP_CPP_E_SIN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_sinh.obj" : $(SOURCE) $(DEP_CPP_E_SIN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_sqrt.c\r
-DEP_CPP_E_SQR=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_sqrt.obj" : $(SOURCE) $(DEP_CPP_E_SQR) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm.h\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\k_cos.c\r
-DEP_CPP_K_COS=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\k_cos.obj" : $(SOURCE) $(DEP_CPP_K_COS) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\k_rem_pio2.c\r
-DEP_CPP_K_REM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\k_rem_pio2.obj" : $(SOURCE) $(DEP_CPP_K_REM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\k_sin.c\r
-DEP_CPP_K_SIN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\k_sin.obj" : $(SOURCE) $(DEP_CPP_K_SIN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\k_standard.c\r
-DEP_CPP_K_STA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\k_standard.obj" : $(SOURCE) $(DEP_CPP_K_STA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\k_tan.c\r
-DEP_CPP_K_TAN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\k_tan.obj" : $(SOURCE) $(DEP_CPP_K_TAN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_asinh.c\r
-DEP_CPP_S_ASI=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_asinh.obj" : $(SOURCE) $(DEP_CPP_S_ASI) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_atan.c\r
-DEP_CPP_S_ATA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_atan.obj" : $(SOURCE) $(DEP_CPP_S_ATA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_cbrt.c\r
-DEP_CPP_S_CBR=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_cbrt.obj" : $(SOURCE) $(DEP_CPP_S_CBR) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_ceil.c\r
-DEP_CPP_S_CEI=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_ceil.obj" : $(SOURCE) $(DEP_CPP_S_CEI) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_copysign.c\r
-DEP_CPP_S_COP=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_copysign.obj" : $(SOURCE) $(DEP_CPP_S_COP) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_cos.c\r
-DEP_CPP_S_COS=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_cos.obj" : $(SOURCE) $(DEP_CPP_S_COS) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_erf.c\r
-DEP_CPP_S_ERF=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_erf.obj" : $(SOURCE) $(DEP_CPP_S_ERF) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_expm1.c\r
-DEP_CPP_S_EXP=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_expm1.obj" : $(SOURCE) $(DEP_CPP_S_EXP) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_fabs.c\r
-DEP_CPP_S_FAB=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_fabs.obj" : $(SOURCE) $(DEP_CPP_S_FAB) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_finite.c\r
-DEP_CPP_S_FIN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_finite.obj" : $(SOURCE) $(DEP_CPP_S_FIN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_floor.c\r
-DEP_CPP_S_FLO=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_floor.obj" : $(SOURCE) $(DEP_CPP_S_FLO) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_frexp.c\r
-DEP_CPP_S_FRE=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_frexp.obj" : $(SOURCE) $(DEP_CPP_S_FRE) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_ilogb.c\r
-DEP_CPP_S_ILO=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_ilogb.obj" : $(SOURCE) $(DEP_CPP_S_ILO) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_isnan.c\r
-DEP_CPP_S_ISN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_isnan.obj" : $(SOURCE) $(DEP_CPP_S_ISN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_ldexp.c\r
-DEP_CPP_S_LDE=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_ldexp.obj" : $(SOURCE) $(DEP_CPP_S_LDE) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_lib_version.c\r
-DEP_CPP_S_LIB=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_lib_version.obj" : $(SOURCE) $(DEP_CPP_S_LIB) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_log1p.c\r
-DEP_CPP_S_LOG=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_log1p.obj" : $(SOURCE) $(DEP_CPP_S_LOG) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_logb.c\r
-DEP_CPP_S_LOGB=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_logb.obj" : $(SOURCE) $(DEP_CPP_S_LOGB) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_matherr.c\r
-DEP_CPP_S_MAT=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_matherr.obj" : $(SOURCE) $(DEP_CPP_S_MAT) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_modf.c\r
-DEP_CPP_S_MOD=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_modf.obj" : $(SOURCE) $(DEP_CPP_S_MOD) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_nextafter.c\r
-DEP_CPP_S_NEX=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_nextafter.obj" : $(SOURCE) $(DEP_CPP_S_NEX) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_rint.c\r
-DEP_CPP_S_RIN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_rint.obj" : $(SOURCE) $(DEP_CPP_S_RIN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_scalbn.c\r
-DEP_CPP_S_SCA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_scalbn.obj" : $(SOURCE) $(DEP_CPP_S_SCA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_signgam.c\r
-DEP_CPP_S_SIG=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_signgam.obj" : $(SOURCE) $(DEP_CPP_S_SIG) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_significand.c\r
-DEP_CPP_S_SIGN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_significand.obj" : $(SOURCE) $(DEP_CPP_S_SIGN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_sin.c\r
-DEP_CPP_S_SIN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_sin.obj" : $(SOURCE) $(DEP_CPP_S_SIN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_tan.c\r
-DEP_CPP_S_TAN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_tan.obj" : $(SOURCE) $(DEP_CPP_S_TAN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\s_tanh.c\r
-DEP_CPP_S_TANH=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_tanh.obj" : $(SOURCE) $(DEP_CPP_S_TANH) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_acos.c\r
-DEP_CPP_W_ACO=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_acos.obj" : $(SOURCE) $(DEP_CPP_W_ACO) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_acosh.c\r
-DEP_CPP_W_ACOS=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_acosh.obj" : $(SOURCE) $(DEP_CPP_W_ACOS) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_asin.c\r
-DEP_CPP_W_ASI=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_asin.obj" : $(SOURCE) $(DEP_CPP_W_ASI) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_atan2.c\r
-DEP_CPP_W_ATA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_atan2.obj" : $(SOURCE) $(DEP_CPP_W_ATA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_atanh.c\r
-DEP_CPP_W_ATAN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_atanh.obj" : $(SOURCE) $(DEP_CPP_W_ATAN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_cosh.c\r
-DEP_CPP_W_COS=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_cosh.obj" : $(SOURCE) $(DEP_CPP_W_COS) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_exp.c\r
-DEP_CPP_W_EXP=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_exp.obj" : $(SOURCE) $(DEP_CPP_W_EXP) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_fmod.c\r
-DEP_CPP_W_FMO=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_fmod.obj" : $(SOURCE) $(DEP_CPP_W_FMO) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_gamma.c\r
-DEP_CPP_W_GAM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_gamma.obj" : $(SOURCE) $(DEP_CPP_W_GAM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_gamma_r.c\r
-DEP_CPP_W_GAMM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_gamma_r.obj" : $(SOURCE) $(DEP_CPP_W_GAMM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_hypot.c\r
-DEP_CPP_W_HYP=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_hypot.obj" : $(SOURCE) $(DEP_CPP_W_HYP) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_j0.c\r
-DEP_CPP_W_J0_=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_j0.obj" : $(SOURCE) $(DEP_CPP_W_J0_) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_j1.c\r
-DEP_CPP_W_J1_=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_j1.obj" : $(SOURCE) $(DEP_CPP_W_J1_) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_jn.c\r
-DEP_CPP_W_JN_=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_jn.obj" : $(SOURCE) $(DEP_CPP_W_JN_) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_lgamma.c\r
-DEP_CPP_W_LGA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_lgamma.obj" : $(SOURCE) $(DEP_CPP_W_LGA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_lgamma_r.c\r
-DEP_CPP_W_LGAM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_lgamma_r.obj" : $(SOURCE) $(DEP_CPP_W_LGAM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_log.c\r
-DEP_CPP_W_LOG=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_log.obj" : $(SOURCE) $(DEP_CPP_W_LOG) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_log10.c\r
-DEP_CPP_W_LOG1=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_log10.obj" : $(SOURCE) $(DEP_CPP_W_LOG1) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_pow.c\r
-DEP_CPP_W_POW=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_pow.obj" : $(SOURCE) $(DEP_CPP_W_POW) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_remainder.c\r
-DEP_CPP_W_REM=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_remainder.obj" : $(SOURCE) $(DEP_CPP_W_REM) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_scalb.c\r
-DEP_CPP_W_SCA=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_scalb.obj" : $(SOURCE) $(DEP_CPP_W_SCA) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\w_sinh.c\r
-DEP_CPP_W_SIN=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_sinh.obj" : $(SOURCE) $(DEP_CPP_W_SIN) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\e_acos.c\r
-DEP_CPP_E_ACOS=\\r
-       ".\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_acos.obj" : $(SOURCE) $(DEP_CPP_E_ACOS) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-# End Target\r
-# End Project\r
-################################################################################\r
diff --git a/src/dom/js/fdlibm/fdlibm.mdp b/src/dom/js/fdlibm/fdlibm.mdp
deleted file mode 100644 (file)
index 5904c49..0000000
Binary files a/src/dom/js/fdlibm/fdlibm.mdp and /dev/null differ
index 17b505d5880b29a4998fb0045d012929650192b5..1d18c803433fa37d440bac9c85858b2f9e9e4081 100644 (file)
@@ -107,7 +107,8 @@ C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
 #endif
 {
         fd_twoints u;
-       double a,hz,z,r,qx;
+        double qx = 0;
+       double a,hz,z,r;
        int ix;
         u.d = x;
        ix = __HI(u)&0x7fffffff;        /* ix = |x|'s high word*/
index 77c778b9277ba30684f7c168aa76eaaefc6c8e8d..b3961667061d0e888244e3e0f5d9af5382455683 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
 #include <io.h>     /* for isatty() */
 #endif
 
-#define EXITCODE_RUNTIME_ERROR 3
-#define EXITCODE_FILE_NOT_FOUND 4
+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;
@@ -101,133 +105,6 @@ JSBool gQuitting = JS_FALSE;
 FILE *gErrFile = NULL;
 FILE *gOutFile = NULL;
 
-#ifdef XP_MAC
-#if defined(MAC_TEST_HACK) || defined(XP_MAC_MPW)
-/* this is the data file that all Print strings will be echoed into */
-FILE *gTestResultFile = NULL;
-#define isatty(f) 0
-#else
-#define isatty(f) 1
-#endif
-
-char *strdup(const char *str)
-{
-    char *copy = (char *) malloc(strlen(str)+1);
-    if (copy)
-        strcpy(copy, str);
-    return copy;
-}
-
-#ifdef XP_MAC_MPW
-/* Macintosh MPW replacements for the ANSI routines.  These translate LF's to CR's because
-   the MPW libraries supplied by Metrowerks don't do that for some reason.  */
-static void translateLFtoCR(char *str, int length)
-{
-    char *limit = str + length;
-    while (str != limit) {
-        if (*str == '\n')
-            *str = '\r';
-        str++;
-    }
-}
-
-int fputc(int c, FILE *file)
-{
-    char buffer = c;
-    if (buffer == '\n')
-        buffer = '\r';
-    return fwrite(&buffer, 1, 1, file);
-}
-
-int fputs(const char *s, FILE *file)
-{
-    char buffer[4096];
-    int n = strlen(s);
-    int extra = 0;
-
-    while (n > sizeof buffer) {
-        memcpy(buffer, s, sizeof buffer);
-        translateLFtoCR(buffer, sizeof buffer);
-        extra += fwrite(buffer, 1, sizeof buffer, file);
-        n -= sizeof buffer;
-        s += sizeof buffer;
-    }
-    memcpy(buffer, s, n);
-    translateLFtoCR(buffer, n);
-    return extra + fwrite(buffer, 1, n, file);
-}
-
-int fprintf(FILE* file, const char *format, ...)
-{
-    va_list args;
-    char smallBuffer[4096];
-    int n;
-    int bufferSize = sizeof smallBuffer;
-    char *buffer = smallBuffer;
-    int result;
-
-    va_start(args, format);
-    n = vsnprintf(buffer, bufferSize, format, args);
-    va_end(args);
-    while (n < 0) {
-        if (buffer != smallBuffer)
-            free(buffer);
-        bufferSize <<= 1;
-        buffer = malloc(bufferSize);
-        if (!buffer) {
-            JS_ASSERT(JS_FALSE);
-            return 0;
-        }
-        va_start(args, format);
-        n = vsnprintf(buffer, bufferSize, format, args);
-        va_end(args);
-    }
-    translateLFtoCR(buffer, n);
-    result = fwrite(buffer, 1, n, file);
-    if (buffer != smallBuffer)
-        free(buffer);
-    return result;
-}
-
-
-#else
-#include <SIOUX.h>
-#include <MacTypes.h>
-
-static char* mac_argv[] = { "js", NULL };
-
-static void initConsole(StringPtr consoleName, const char* startupMessage, int *argc, char** *argv)
-{
-    SIOUXSettings.autocloseonquit = true;
-    SIOUXSettings.asktosaveonclose = false;
-    /* SIOUXSettings.initializeTB = false;
-     SIOUXSettings.showstatusline = true;*/
-    puts(startupMessage);
-    SIOUXSetTitle(consoleName);
-
-    /* set up a buffer for stderr (otherwise it's a pig). */
-    setvbuf(stderr, (char *) malloc(BUFSIZ), _IOLBF, BUFSIZ);
-
-    *argc = 1;
-    *argv = mac_argv;
-}
-
-#ifdef LIVECONNECT
-/* Little hack to provide a default CLASSPATH on the Mac. */
-#define getenv(var) mac_getenv(var)
-static char* mac_getenv(const char* var)
-{
-    if (strcmp(var, "CLASSPATH") == 0) {
-        static char class_path[] = "liveconnect.jar";
-        return class_path;
-    }
-    return NULL;
-}
-#endif /* LIVECONNECT */
-
-#endif
-#endif
-
 #ifdef JSDEBUGGER
 static JSDContext *_jsdc;
 #ifdef JSDEBUGGER_JAVA_UI
@@ -236,6 +113,7 @@ static JSDJContext *_jsdjc;
 #endif /* JSDEBUGGER */
 
 static JSBool reportWarnings = JS_TRUE;
+static JSBool compileOnly = JS_FALSE;
 
 typedef enum JSShellErrNum {
 #define MSG_DEF(name, number, count, exception, format) \
@@ -278,10 +156,6 @@ GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
         char line[256];
         fprintf(gOutFile, prompt);
         fflush(gOutFile);
-#ifdef XP_MAC_MPW
-        /* Print a CR after the prompt because MPW grabs the entire line when entering an interactive command */
-        fputc('\n', gOutFile);
-#endif
         if (!fgets(line, sizeof line, file))
             return JS_FALSE;
         strcpy(bufp, line);
@@ -348,7 +222,8 @@ Process(JSContext *cx, JSObject *obj, char *filename)
         ungetc(ch, file);
         script = JS_CompileFileHandle(cx, obj, filename, file);
         if (script) {
-            (void)JS_ExecuteScript(cx, obj, script, &result);
+            if (!compileOnly)
+                (void)JS_ExecuteScript(cx, obj, script, &result);
             JS_DestroyScript(cx, script);
         }
         return;
@@ -379,21 +254,18 @@ Process(JSContext *cx, JSObject *obj, char *filename)
 
         /* Clear any pending exception from previous failed compiles.  */
         JS_ClearPendingException(cx);
-        script = JS_CompileScript(cx, obj, buffer, strlen(buffer),
-#ifdef JSDEBUGGER
-                                  "typein",
-#else
-                                  NULL,
-#endif
+        script = JS_CompileScript(cx, obj, buffer, strlen(buffer), "typein",
                                   startline);
         if (script) {
-            ok = JS_ExecuteScript(cx, obj, script, &result);
-            if (ok && result != JSVAL_VOID) {
-                str = JS_ValueToString(cx, result);
-                if (str)
-                    fprintf(gOutFile, "%s\n", JS_GetStringBytes(str));
-                else
-                    ok = JS_FALSE;
+            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);
         }
@@ -406,7 +278,7 @@ static int
 usage(void)
 {
     fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
-    fprintf(gErrFile, "usage: js [-PswW] [-b branchlimit] [-c stackchunksize] [-v version] [-f scriptfile] [-S maxstacksize] [scriptfile] [scriptarg...]\n");
+    fprintf(gErrFile, "usage: js [-PswWxC] [-b branchlimit] [-c stackchunksize] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] [scriptfile] [scriptarg...]\n");
     return 2;
 }
 
@@ -417,10 +289,15 @@ static JSBool
 my_BranchCallback(JSContext *cx, JSScript *script)
 {
     if (++gBranchCount == gBranchLimit) {
-        if (script->filename)
-            fprintf(gErrFile, "%s:", script->filename);
-        fprintf(gErrFile, "%u: script branches too much (%u callbacks)\n",
-                script->lineno, gBranchLimit);
+        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;
     }
@@ -454,10 +331,12 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
           case 'b':
           case 'c':
           case 'f':
+          case 'e':
           case 'v':
           case 'S':
             ++i;
             break;
+          default:;
         }
     }
 
@@ -511,6 +390,10 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
             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;
@@ -531,6 +414,7 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
         case 'b':
             gBranchLimit = atoi(argv[++i]);
             JS_SetBranchCallback(cx, my_BranchCallback);
+            JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK);
             break;
 
         case 'c':
@@ -545,12 +429,33 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
             Process(cx, obj, argv[i]);
             /*
              * XXX: js -f foo.js should interpret foo.js and then
-             * drop into interactive mode, but that breaks test
+             * 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();
@@ -587,6 +492,7 @@ static struct {
     {"strict",          JSOPTION_STRICT},
     {"werror",          JSOPTION_WERROR},
     {"atline",          JSOPTION_ATLINE},
+    {"xml",             JSOPTION_XML},
     {0,                 0}
 };
 
@@ -677,7 +583,9 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         if (!script) {
             ok = JS_FALSE;
         } else {
-            ok = JS_ExecuteScript(cx, obj, script, &result);
+            ok = !compileOnly
+                 ? JS_ExecuteScript(cx, obj, script, &result)
+                 : JS_TRUE;
             JS_DestroyScript(cx, script);
         }
         JS_SetOptions(cx, oldopts);
@@ -689,6 +597,77 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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)
 {
@@ -723,10 +702,6 @@ Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     return JS_FALSE;
 }
 
-#ifdef GC_MARK_DEBUG
-extern JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
-#endif
-
 static JSBool
 GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
@@ -774,7 +749,7 @@ ValueToScript(JSContext *cx, jsval v)
     JSScript *script;
     JSFunction *fun;
 
-    if (JSVAL_IS_OBJECT(v) &&
+    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 {
@@ -790,15 +765,19 @@ 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 (JS_TypeOfValue(cx, argv[0]) == JSTYPE_FUNCTION) {
-            script = ValueToScript(cx, argv[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;
@@ -1052,7 +1031,8 @@ Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             }
         }
 
-        js_Disassemble(cx, script, lines, stdout);
+        if (!js_Disassemble(cx, script, lines, stdout))
+            return JS_FALSE;
         SrcNotes(cx, script);
         TryNotes(cx, script);
     }
@@ -1114,8 +1094,8 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                 while (line1 < line2) {
                     if (!fgets(linebuf, LINE_BUF_LEN, file)) {
                         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
-                                       JSSMSG_UNEXPECTED_EOF,
-                                       script->filename);
+                                             JSSMSG_UNEXPECTED_EOF,
+                                             script->filename);
                         goto bail;
                     }
                     line1++;
@@ -1206,11 +1186,14 @@ DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
         if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
             continue;
         fprintf(fp, "%3u %p", i, sprop);
-        if (JSVAL_IS_INT(sprop->id)) {
+        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 {
-            fprintf(fp, " \"%s\"",
-                    js_AtomToPrintableString(cx, (JSAtom *)sprop->id));
+            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)
@@ -1267,11 +1250,11 @@ DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             atom = js_Atomize(cx, bytes, JS_GetStringLength(str), 0);
             if (!atom)
                 return JS_FALSE;
-            if (!js_FindProperty(cx, (jsid)atom, &obj, &obj2, &prop))
+            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, (jsid)atom, &value))
+                if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &value))
                     return JS_FALSE;
             }
             if (!prop || !JSVAL_IS_OBJECT(value)) {
@@ -1309,16 +1292,16 @@ DoExport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     atom = js_ValueToStringAtom(cx, argv[1]);
     if (!atom)
         return JS_FALSE;
-    if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
+    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, (jsid)atom, prop, &attrs);
+        ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
         if (ok) {
             attrs |= JSPROP_EXPORTED;
-            ok = OBJ_SET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
+            ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
         }
         OBJ_DROP_PROPERTY(cx, obj2, prop);
     }
@@ -1509,10 +1492,131 @@ Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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},
@@ -1521,6 +1625,8 @@ static JSFunctionSpec shell_functions[] = {
     {"untrap",          Untrap,         2},
     {"line2pc",         LineToPC,       0},
     {"pc2line",         PCToLine,       0},
+    {"stringsAreUtf8",  StringsAreUtf8, 0},
+    {"testUtf8",        TestUtf8,       1},
 #ifdef DEBUG
     {"dis",             Disassemble,    1},
     {"dissrc",          DisassWithSrc,  1},
@@ -1539,6 +1645,9 @@ static JSFunctionSpec shell_functions[] = {
     {"intern",          Intern,         1},
     {"clone",           Clone,          1},
     {"seal",            Seal,           1, 0, 1},
+    {"getpda",          GetPDA,         1},
+    {"getslx",          GetSLX,         1},
+    {"toint32",         ToInt32,        1},
     {0}
 };
 
@@ -1548,6 +1657,7 @@ 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",
@@ -1556,6 +1666,8 @@ static char *shell_help_messages[] = {
     "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",
@@ -1574,20 +1686,23 @@ static char *shell_help_messages[] = {
     "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, "%-9s %-22s %s\n", "Command", "Usage", "Description");
-    fprintf(gOutFile, "%-9s %-22s %s\n", "=======", "=====", "===========");
+    fprintf(gOutFile, "%-14s %-22s %s\n", "Command", "Usage", "Description");
+    fprintf(gOutFile, "%-14s %-22s %s\n", "=======", "=====", "===========");
 }
 
 static void
 ShowHelpForCommand(uintN n)
 {
-    fprintf(gOutFile, "%-9.9s %s\n", shell_functions[n].name, shell_help_messages[n]);
+    fprintf(gOutFile, "%-14.14s %s\n", shell_functions[n].name, shell_help_messages[n]);
 }
 
 static JSBool
@@ -1671,8 +1786,36 @@ its_item(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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}
 };
 
@@ -1917,8 +2060,13 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
     }
     fputs("^\n", gErrFile);
  out:
-    if (!JSREPORT_IS_WARNING(report->flags))
-        gExitCode = EXITCODE_RUNTIME_ERROR;
+    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);
 }
 
@@ -2204,14 +2352,89 @@ defineProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                                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 <fcntl.h>
 #include <sys/stat.h>
 
+/*
+ * 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;
@@ -2222,15 +2445,23 @@ snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     if (!str)
         return JS_FALSE;
     filename = JS_GetStringBytes(str);
-    fd = open(filename, O_RDONLY);
+    
+    /* 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", filename, strerror(errno));
+        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", filename);
+        JS_ReportError(cx, "can't stat %s", pathname);
         ok = JS_FALSE;
     } else {
         len = sb.st_size;
@@ -2239,12 +2470,13 @@ snarf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             ok = JS_FALSE;
         } else if ((cc = read(fd, buf, len)) != len) {
             JS_free(cx, buf);
-            JS_ReportError(cx, "can't read %s: %s", filename,
+            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';
@@ -2263,7 +2495,6 @@ int
 main(int argc, char **argv, char **envp)
 {
     int stackDummy;
-    JSVersion version;
     JSRuntime *rt;
     JSContext *cx;
     JSObject *glob, *it, *envobj;
@@ -2287,47 +2518,6 @@ main(int argc, char **argv, char **envp)
     gErrFile = stderr;
     gOutFile = stdout;
 
-#ifdef XP_MAC
-#ifndef XP_MAC_MPW
-    initConsole("\pJavaScript Shell", "Welcome to js shell.", &argc, &argv);
-#endif
-#endif
-
-#ifdef MAC_TEST_HACK
-/*
-    Open a file "testArgs.txt" and read each line into argc/argv.
-    Re-direct all output to "results.txt"
-*/
-    {
-        char argText[256];
-        FILE *f = fopen("testargs.txt", "r");
-        if (f) {
-            int maxArgs = 32; /* arbitrary max !!! */
-            int argText_strlen;
-            argc = 1;
-            argv = malloc(sizeof(char *) * maxArgs);
-            argv[0] = NULL;
-            while (fgets(argText, 255, f)) {
-                 /* argText includes '\n' */
-                argText_strlen = strlen(argText);
-                argv[argc] = malloc(argText_strlen);
-                strncpy(argv[argc], argText, argText_strlen - 1);
-                argv[argc][argText_strlen - 1] = '\0';
-                argc++;
-                if (argc >= maxArgs)
-                    break;
-            }
-            fclose(f);
-        }
-        gTestResultFile = fopen("results.txt", "w");
-    }
-
-    gErrFile = gTestResultFile;
-    gOutFile = gTestResultFile;
-#endif
-
-    version = JSVERSION_DEFAULT;
-
     argc--;
     argv++;
 
@@ -2352,10 +2542,6 @@ main(int argc, char **argv, char **envp)
     if (!JS_DefineFunctions(cx, glob, shell_functions))
         return 1;
 
-    /* Set version only after there is a global object. */
-    if (version != JSVERSION_DEFAULT)
-        JS_SetVersion(cx, version);
-
     it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0);
     if (!it)
         return 1;
@@ -2417,6 +2603,9 @@ main(int argc, char **argv, char **envp)
 
         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)) {
@@ -2436,10 +2625,6 @@ main(int argc, char **argv, char **envp)
         JSD_DebuggerOff(_jsdc);
 #endif  /* JSDEBUGGER */
 
-#ifdef MAC_TEST_HACK
-    fclose(gTestResultFile);
-#endif
-
     JS_DestroyContext(cx);
     JS_DestroyRuntime(rt);
     JS_ShutDown();
diff --git a/src/dom/js/js.mak b/src/dom/js/js.mak
deleted file mode 100644 (file)
index a155abf..0000000
+++ /dev/null
@@ -1,4025 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
-# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
-\r
-!IF "$(CFG)" == ""\r
-CFG=jsshell - Win32 Debug\r
-!MESSAGE No configuration specified.  Defaulting to jsshell - Win32 Debug.\r
-!ENDIF \r
-\r
-!IF "$(CFG)" != "js - Win32 Release" && "$(CFG)" != "js - Win32 Debug" &&\\r
- "$(CFG)" != "jsshell - Win32 Release" && "$(CFG)" != "jsshell - Win32 Debug" &&\\r
- "$(CFG)" != "fdlibm - Win32 Release" && "$(CFG)" != "fdlibm - Win32 Debug"\r
-!MESSAGE Invalid configuration "$(CFG)" specified.\r
-!MESSAGE You can specify a configuration when running NMAKE on this makefile\r
-!MESSAGE by defining the macro CFG on the command line.  For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "js.mak" CFG="jsshell - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "js - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE "js - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE "jsshell - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "jsshell - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "fdlibm - Win32 Release" (based on "Win32 (x86) Static Library")\r
-!MESSAGE "fdlibm - Win32 Debug" (based on "Win32 (x86) Static Library")\r
-!MESSAGE \r
-!ERROR An invalid configuration is specified.\r
-!ENDIF \r
-\r
-!IF "$(OS)" == "Windows_NT"\r
-NULL=\r
-!ELSE \r
-NULL=nul\r
-!ENDIF \r
-################################################################################\r
-# Begin Project\r
-# PROP Target_Last_Scanned "jsshell - Win32 Debug"\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "js___Wi1"\r
-# PROP BASE Intermediate_Dir "js___Wi1"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir "Release"\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-OUTDIR=.\Release\r
-INTDIR=.\Release\r
-\r
-ALL : "fdlibm - Win32 Release" "$(OUTDIR)\js32.dll"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\jsapi.obj"\r
-       -@erase "$(INTDIR)\jsarena.obj"\r
-       -@erase "$(INTDIR)\jsarray.obj"\r
-       -@erase "$(INTDIR)\jsatom.obj"\r
-       -@erase "$(INTDIR)\jsbool.obj"\r
-       -@erase "$(INTDIR)\jscntxt.obj"\r
-       -@erase "$(INTDIR)\jsdate.obj"\r
-       -@erase "$(INTDIR)\jsdbgapi.obj"\r
-       -@erase "$(INTDIR)\jsdhash.obj"\r
-       -@erase "$(INTDIR)\jsdtoa.obj"\r
-       -@erase "$(INTDIR)\jsemit.obj"\r
-       -@erase "$(INTDIR)\jsexn.obj"\r
-       -@erase "$(INTDIR)\jsfun.obj"\r
-       -@erase "$(INTDIR)\jsgc.obj"\r
-       -@erase "$(INTDIR)\jshash.obj"\r
-       -@erase "$(INTDIR)\jsinterp.obj"\r
-       -@erase "$(INTDIR)\jslock.obj"\r
-       -@erase "$(INTDIR)\jslog2.obj"\r
-       -@erase "$(INTDIR)\jslong.obj"\r
-       -@erase "$(INTDIR)\jsmath.obj"\r
-       -@erase "$(INTDIR)\jsnum.obj"\r
-       -@erase "$(INTDIR)\jsobj.obj"\r
-       -@erase "$(INTDIR)\jsopcode.obj"\r
-       -@erase "$(INTDIR)\jsparse.obj"\r
-       -@erase "$(INTDIR)\jsprf.obj"\r
-       -@erase "$(INTDIR)\jsregexp.obj"\r
-       -@erase "$(INTDIR)\jsscan.obj"\r
-       -@erase "$(INTDIR)\jsscope.obj"\r
-       -@erase "$(INTDIR)\jsscript.obj"\r
-       -@erase "$(INTDIR)\jsstr.obj"\r
-       -@erase "$(INTDIR)\jsutil.obj"\r
-       -@erase "$(INTDIR)\jsxdrapi.obj"\r
-       -@erase "$(INTDIR)\prmjtime.obj"\r
-       -@erase "$(OUTDIR)\js32.dll"\r
-       -@erase "$(OUTDIR)\js32.exp"\r
-       -@erase "$(OUTDIR)\js32.lib"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-CPP=cl.exe\r
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c\r
-# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /YX /c\r
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /D "WIN32" /D\\r
- "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /Fp"$(INTDIR)/js.pch" /YX\\r
- /Fo"$(INTDIR)/" /c \r
-CPP_OBJS=.\Release/\r
-CPP_SBRS=.\.\r
-\r
-.c{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.c{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-MTL=mktyplib.exe\r
-# ADD BASE MTL /nologo /D "NDEBUG" /win32\r
-# ADD MTL /nologo /D "NDEBUG" /win32\r
-MTL_PROJ=/nologo /D "NDEBUG" /win32 \r
-RSC=rc.exe\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/js.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/js32.dll"\r
-# SUBTRACT LINK32 /nodefaultlib\r
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\\r
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\\r
- odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\\r
- /pdb:"$(OUTDIR)/js32.pdb" /machine:I386 /out:"$(OUTDIR)/js32.dll"\\r
- /implib:"$(OUTDIR)/js32.lib" /opt:ref /opt:noicf\r
-LINK32_OBJS= \\r
-       "$(INTDIR)\jsapi.obj" \\r
-       "$(INTDIR)\jsarena.obj" \\r
-       "$(INTDIR)\jsarray.obj" \\r
-       "$(INTDIR)\jsatom.obj" \\r
-       "$(INTDIR)\jsbool.obj" \\r
-       "$(INTDIR)\jscntxt.obj" \\r
-       "$(INTDIR)\jsdate.obj" \\r
-       "$(INTDIR)\jsdbgapi.obj" \\r
-       "$(INTDIR)\jsdhash.obj" \\r
-       "$(INTDIR)\jsdtoa.obj" \\r
-       "$(INTDIR)\jsemit.obj" \\r
-       "$(INTDIR)\jsexn.obj" \\r
-       "$(INTDIR)\jsfun.obj" \\r
-       "$(INTDIR)\jsgc.obj" \\r
-       "$(INTDIR)\jshash.obj" \\r
-       "$(INTDIR)\jsinterp.obj" \\r
-       "$(INTDIR)\jslock.obj" \\r
-       "$(INTDIR)\jslog2.obj" \\r
-       "$(INTDIR)\jslong.obj" \\r
-       "$(INTDIR)\jsmath.obj" \\r
-       "$(INTDIR)\jsnum.obj" \\r
-       "$(INTDIR)\jsobj.obj" \\r
-       "$(INTDIR)\jsopcode.obj" \\r
-       "$(INTDIR)\jsparse.obj" \\r
-       "$(INTDIR)\jsprf.obj" \\r
-       "$(INTDIR)\jsregexp.obj" \\r
-       "$(INTDIR)\jsscan.obj" \\r
-       "$(INTDIR)\jsscope.obj" \\r
-       "$(INTDIR)\jsscript.obj" \\r
-       "$(INTDIR)\jsstr.obj" \\r
-       "$(INTDIR)\jsutil.obj" \\r
-       "$(INTDIR)\jsxdrapi.obj" \\r
-       "$(INTDIR)\prmjtime.obj" \\r
-       "$(OUTDIR)\fdlibm.lib"\r
-\r
-"$(OUTDIR)\js32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
-    $(LINK32) @<<\r
-  $(LINK32_FLAGS) $(LINK32_OBJS)\r
-<<\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "js___Wi2"\r
-# PROP BASE Intermediate_Dir "js___Wi2"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir "Debug"\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-OUTDIR=.\Debug\r
-INTDIR=.\Debug\r
-\r
-ALL : "fdlibm - Win32 Debug" "$(OUTDIR)\js32.dll"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\jsapi.obj"\r
-       -@erase "$(INTDIR)\jsarena.obj"\r
-       -@erase "$(INTDIR)\jsarray.obj"\r
-       -@erase "$(INTDIR)\jsatom.obj"\r
-       -@erase "$(INTDIR)\jsbool.obj"\r
-       -@erase "$(INTDIR)\jscntxt.obj"\r
-       -@erase "$(INTDIR)\jsdate.obj"\r
-       -@erase "$(INTDIR)\jsdbgapi.obj"\r
-       -@erase "$(INTDIR)\jsdhash.obj"\r
-       -@erase "$(INTDIR)\jsdtoa.obj"\r
-       -@erase "$(INTDIR)\jsemit.obj"\r
-       -@erase "$(INTDIR)\jsexn.obj"\r
-       -@erase "$(INTDIR)\jsfun.obj"\r
-       -@erase "$(INTDIR)\jsgc.obj"\r
-       -@erase "$(INTDIR)\jshash.obj"\r
-       -@erase "$(INTDIR)\jsinterp.obj"\r
-       -@erase "$(INTDIR)\jslock.obj"\r
-       -@erase "$(INTDIR)\jslog2.obj"\r
-       -@erase "$(INTDIR)\jslong.obj"\r
-       -@erase "$(INTDIR)\jsmath.obj"\r
-       -@erase "$(INTDIR)\jsnum.obj"\r
-       -@erase "$(INTDIR)\jsobj.obj"\r
-       -@erase "$(INTDIR)\jsopcode.obj"\r
-       -@erase "$(INTDIR)\jsparse.obj"\r
-       -@erase "$(INTDIR)\jsprf.obj"\r
-       -@erase "$(INTDIR)\jsregexp.obj"\r
-       -@erase "$(INTDIR)\jsscan.obj"\r
-       -@erase "$(INTDIR)\jsscope.obj"\r
-       -@erase "$(INTDIR)\jsscript.obj"\r
-       -@erase "$(INTDIR)\jsstr.obj"\r
-       -@erase "$(INTDIR)\jsutil.obj"\r
-       -@erase "$(INTDIR)\jsxdrapi.obj"\r
-       -@erase "$(INTDIR)\prmjtime.obj"\r
-       -@erase "$(INTDIR)\vc40.idb"\r
-       -@erase "$(INTDIR)\vc40.pdb"\r
-       -@erase "$(OUTDIR)\js32.dll"\r
-       -@erase "$(OUTDIR)\js32.exp"\r
-       -@erase "$(OUTDIR)\js32.ilk"\r
-       -@erase "$(OUTDIR)\js32.lib"\r
-       -@erase "$(OUTDIR)\js32.pdb"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-CPP=cl.exe\r
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c\r
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "DEBUG" /D _X86_=1 /D "_WINDOWS" /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /YX /c\r
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "DEBUG" /D _X86_=1 /D "_WINDOWS"\\r
- /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "EXPORT_JS_API" /Fp"$(INTDIR)/js.pch" /YX\\r
- /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c \r
-CPP_OBJS=.\Debug/\r
-CPP_SBRS=.\.\r
-\r
-.c{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.c{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-MTL=mktyplib.exe\r
-# ADD BASE MTL /nologo /D "_DEBUG" /win32\r
-# ADD MTL /nologo /D "_DEBUG" /win32\r
-MTL_PROJ=/nologo /D "_DEBUG" /win32 \r
-RSC=rc.exe\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/js.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/js32.dll"\r
-# SUBTRACT LINK32 /nodefaultlib\r
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\\r
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\\r
- odbccp32.lib /nologo /subsystem:windows /dll /incremental:yes\\r
- /pdb:"$(OUTDIR)/js32.pdb" /debug /machine:I386 /out:"$(OUTDIR)/js32.dll"\\r
- /implib:"$(OUTDIR)/js32.lib" \r
-LINK32_OBJS= \\r
-       "$(INTDIR)\jsapi.obj" \\r
-       "$(INTDIR)\jsarena.obj" \\r
-       "$(INTDIR)\jsarray.obj" \\r
-       "$(INTDIR)\jsatom.obj" \\r
-       "$(INTDIR)\jsbool.obj" \\r
-       "$(INTDIR)\jscntxt.obj" \\r
-       "$(INTDIR)\jsdate.obj" \\r
-       "$(INTDIR)\jsdbgapi.obj" \\r
-       "$(INTDIR)\jsdhash.obj" \\r
-       "$(INTDIR)\jsdtoa.obj" \\r
-       "$(INTDIR)\jsemit.obj" \\r
-       "$(INTDIR)\jsexn.obj" \\r
-       "$(INTDIR)\jsfun.obj" \\r
-       "$(INTDIR)\jsgc.obj" \\r
-       "$(INTDIR)\jshash.obj" \\r
-       "$(INTDIR)\jsinterp.obj" \\r
-       "$(INTDIR)\jslock.obj" \\r
-       "$(INTDIR)\jslog2.obj" \\r
-       "$(INTDIR)\jslong.obj" \\r
-       "$(INTDIR)\jsmath.obj" \\r
-       "$(INTDIR)\jsnum.obj" \\r
-       "$(INTDIR)\jsobj.obj" \\r
-       "$(INTDIR)\jsopcode.obj" \\r
-       "$(INTDIR)\jsparse.obj" \\r
-       "$(INTDIR)\jsprf.obj" \\r
-       "$(INTDIR)\jsregexp.obj" \\r
-       "$(INTDIR)\jsscan.obj" \\r
-       "$(INTDIR)\jsscope.obj" \\r
-       "$(INTDIR)\jsscript.obj" \\r
-       "$(INTDIR)\jsstr.obj" \\r
-       "$(INTDIR)\jsutil.obj" \\r
-       "$(INTDIR)\jsxdrapi.obj" \\r
-       "$(INTDIR)\prmjtime.obj" \\r
-       "$(OUTDIR)\fdlibm.lib"\r
-\r
-"$(OUTDIR)\js32.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
-    $(LINK32) @<<\r
-  $(LINK32_FLAGS) $(LINK32_OBJS)\r
-<<\r
-\r
-!ELSEIF  "$(CFG)" == "jsshell - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "jsshell\Release"\r
-# PROP BASE Intermediate_Dir "jsshell\Release"\r
-# PROP BASE Target_Dir "jsshell"\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir "Release"\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir "jsshell"\r
-OUTDIR=.\Release\r
-INTDIR=.\Release\r
-\r
-ALL : "js - Win32 Release" "$(OUTDIR)\jsshell.exe"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\js.obj"\r
-       -@erase "$(OUTDIR)\jsshell.exe"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-CPP=cl.exe\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c\r
-# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "XP_WIN" /D "JSFILE" /YX /c\r
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D\\r
- "XP_WIN" /D "JSFILE" /Fp"$(INTDIR)/jsshell.pch" /YX /Fo"$(INTDIR)/" /c \r
-CPP_OBJS=.\Release/\r
-CPP_SBRS=.\.\r
-\r
-.c{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.c{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-RSC=rc.exe\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/jsshell.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\\r
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\\r
- odbccp32.lib /nologo /subsystem:console /incremental:no\\r
- /pdb:"$(OUTDIR)/jsshell.pdb" /machine:I386 /out:"$(OUTDIR)/jsshell.exe" \r
-LINK32_OBJS= \\r
-       "$(INTDIR)\js.obj" \\r
-       "$(OUTDIR)\js32.lib"\r
-\r
-"$(OUTDIR)\jsshell.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
-    $(LINK32) @<<\r
-  $(LINK32_FLAGS) $(LINK32_OBJS)\r
-<<\r
-\r
-!ELSEIF  "$(CFG)" == "jsshell - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "jsshell\jsshell_"\r
-# PROP BASE Intermediate_Dir "jsshell\jsshell_"\r
-# PROP BASE Target_Dir "jsshell"\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir "Debug"\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir "jsshell"\r
-OUTDIR=.\Debug\r
-INTDIR=.\Debug\r
-\r
-ALL : "js - Win32 Debug" "$(OUTDIR)\jsshell.exe"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\js.obj"\r
-       -@erase "$(INTDIR)\vc40.idb"\r
-       -@erase "$(INTDIR)\vc40.pdb"\r
-       -@erase "$(OUTDIR)\jsshell.exe"\r
-       -@erase "$(OUTDIR)\jsshell.ilk"\r
-       -@erase "$(OUTDIR)\jsshell.pdb"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-CPP=cl.exe\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c\r
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_CONSOLE" /D "_DEBUG" /D "WIN32" /D "XP_WIN" /D "JSFILE" /D "DEBUG" /YX /c\r
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "_CONSOLE" /D "_DEBUG" /D "WIN32"\\r
- /D "XP_WIN" /D "JSFILE" /D "DEBUG" /Fp"$(INTDIR)/jsshell.pch" /YX\\r
- /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c \r
-CPP_OBJS=.\Debug/\r
-CPP_SBRS=.\.\r
-\r
-.c{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.c{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-RSC=rc.exe\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/jsshell.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386\r
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\\r
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\\r
- odbccp32.lib /nologo /subsystem:console /incremental:yes\\r
- /pdb:"$(OUTDIR)/jsshell.pdb" /debug /machine:I386 /out:"$(OUTDIR)/jsshell.exe" \r
-LINK32_OBJS= \\r
-       "$(INTDIR)\js.obj" \\r
-       "$(OUTDIR)\js32.lib"\r
-\r
-"$(OUTDIR)\jsshell.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)\r
-    $(LINK32) @<<\r
-  $(LINK32_FLAGS) $(LINK32_OBJS)\r
-<<\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "fdlibm\Release"\r
-# PROP BASE Intermediate_Dir "fdlibm\Release"\r
-# PROP BASE Target_Dir "fdlibm"\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir "Release"\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir "fdlibm"\r
-OUTDIR=.\Release\r
-INTDIR=.\Release\r
-\r
-ALL : "$(OUTDIR)\fdlibm.lib"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\e_atan2.obj"\r
-       -@erase "$(INTDIR)\e_pow.obj"\r
-       -@erase "$(INTDIR)\e_sqrt.obj"\r
-       -@erase "$(INTDIR)\k_standard.obj"\r
-       -@erase "$(INTDIR)\s_atan.obj"\r
-       -@erase "$(INTDIR)\s_copysign.obj"\r
-       -@erase "$(INTDIR)\s_fabs.obj"\r
-       -@erase "$(INTDIR)\s_finite.obj"\r
-       -@erase "$(INTDIR)\s_isnan.obj"\r
-       -@erase "$(INTDIR)\s_matherr.obj"\r
-       -@erase "$(INTDIR)\s_rint.obj"\r
-       -@erase "$(INTDIR)\s_scalbn.obj"\r
-       -@erase "$(INTDIR)\w_atan2.obj"\r
-       -@erase "$(INTDIR)\w_pow.obj"\r
-       -@erase "$(INTDIR)\w_sqrt.obj"\r
-       -@erase "$(OUTDIR)\fdlibm.lib"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-CPP=cl.exe\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c\r
-# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D "_IEEE_LIBM" /YX /c\r
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D\\r
- "_IEEE_LIBM" /D "XP_WIN" /I .\ /Fp"$(INTDIR)/fdlibm.pch" /YX /Fo"$(INTDIR)/" /c \r
-CPP_OBJS=.\Release/\r
-CPP_SBRS=.\.\r
-\r
-.c{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.c{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/fdlibm.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LIB32=link.exe -lib\r
-# ADD BASE LIB32 /nologo\r
-# ADD LIB32 /nologo\r
-LIB32_FLAGS=/nologo /out:"$(OUTDIR)/fdlibm.lib" \r
-LIB32_OBJS= \\r
-       "$(INTDIR)\e_atan2.obj" \\r
-       "$(INTDIR)\e_pow.obj" \\r
-       "$(INTDIR)\e_sqrt.obj" \\r
-       "$(INTDIR)\k_standard.obj" \\r
-       "$(INTDIR)\s_atan.obj" \\r
-       "$(INTDIR)\s_copysign.obj" \\r
-       "$(INTDIR)\s_fabs.obj" \\r
-       "$(INTDIR)\s_finite.obj" \\r
-       "$(INTDIR)\s_isnan.obj" \\r
-       "$(INTDIR)\s_matherr.obj" \\r
-       "$(INTDIR)\s_rint.obj" \\r
-       "$(INTDIR)\s_scalbn.obj" \\r
-       "$(INTDIR)\w_atan2.obj" \\r
-       "$(INTDIR)\w_pow.obj" \\r
-       "$(INTDIR)\w_sqrt.obj"\r
-\r
-"$(OUTDIR)\fdlibm.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)\r
-    $(LIB32) @<<\r
-  $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)\r
-<<\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "fdlibm\Debug"\r
-# PROP BASE Intermediate_Dir "fdlibm\Debug"\r
-# PROP BASE Target_Dir "fdlibm"\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir "Debug"\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir "fdlibm"\r
-OUTDIR=.\Debug\r
-INTDIR=.\Debug\r
-\r
-ALL : "$(OUTDIR)\fdlibm.lib"\r
-\r
-CLEAN : \r
-       -@erase "$(INTDIR)\e_atan2.obj"\r
-       -@erase "$(INTDIR)\e_pow.obj"\r
-       -@erase "$(INTDIR)\e_sqrt.obj"\r
-       -@erase "$(INTDIR)\k_standard.obj"\r
-       -@erase "$(INTDIR)\s_atan.obj"\r
-       -@erase "$(INTDIR)\s_copysign.obj"\r
-       -@erase "$(INTDIR)\s_fabs.obj"\r
-       -@erase "$(INTDIR)\s_finite.obj"\r
-       -@erase "$(INTDIR)\s_isnan.obj"\r
-       -@erase "$(INTDIR)\s_matherr.obj"\r
-       -@erase "$(INTDIR)\s_rint.obj"\r
-       -@erase "$(INTDIR)\s_scalbn.obj"\r
-       -@erase "$(INTDIR)\w_atan2.obj"\r
-       -@erase "$(INTDIR)\w_pow.obj"\r
-       -@erase "$(INTDIR)\w_sqrt.obj"\r
-       -@erase "$(OUTDIR)\fdlibm.lib"\r
-\r
-"$(OUTDIR)" :\r
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"\r
-\r
-CPP=cl.exe\r
-# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D _X86_=1 /D "_WINDOWS" /YX /c\r
-# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /D "_DEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D "_IEEE_LIBM" /YX /c\r
-CPP_PROJ=/nologo /MDd /W3 /GX /Z7 /Od /D "_DEBUG" /D "WIN32" /D _X86_=1 /D "_WINDOWS" /D\\r
- "_IEEE_LIBM" /D "XP_WIN" -I .\ /Fp"$(INTDIR)/fdlibm.pch" /YX /Fo"$(INTDIR)/" /c \r
-CPP_OBJS=.\Debug/\r
-CPP_SBRS=.\.\r
-\r
-.c{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_OBJS)}.obj:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.c{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cpp{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-.cxx{$(CPP_SBRS)}.sbr:\r
-   $(CPP) $(CPP_PROJ) $<  \r
-\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/fdlibm.bsc" \r
-BSC32_SBRS= \\r
-       \r
-LIB32=link.exe -lib\r
-# ADD BASE LIB32 /nologo\r
-# ADD LIB32 /nologo\r
-LIB32_FLAGS=/nologo /out:"$(OUTDIR)/fdlibm.lib" \r
-LIB32_OBJS= \\r
-       "$(INTDIR)\e_atan2.obj" \\r
-       "$(INTDIR)\e_pow.obj" \\r
-       "$(INTDIR)\e_sqrt.obj" \\r
-       "$(INTDIR)\k_standard.obj" \\r
-       "$(INTDIR)\s_atan.obj" \\r
-       "$(INTDIR)\s_copysign.obj" \\r
-       "$(INTDIR)\s_fabs.obj" \\r
-       "$(INTDIR)\s_finite.obj" \\r
-       "$(INTDIR)\s_isnan.obj" \\r
-       "$(INTDIR)\s_matherr.obj" \\r
-       "$(INTDIR)\s_rint.obj" \\r
-       "$(INTDIR)\s_scalbn.obj" \\r
-       "$(INTDIR)\w_atan2.obj" \\r
-       "$(INTDIR)\w_pow.obj" \\r
-       "$(INTDIR)\w_sqrt.obj"\r
-\r
-"$(OUTDIR)\fdlibm.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)\r
-    $(LIB32) @<<\r
-  $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)\r
-<<\r
-\r
-!ENDIF \r
-\r
-################################################################################\r
-# Begin Target\r
-\r
-# Name "js - Win32 Release"\r
-# Name "js - Win32 Debug"\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-!ENDIF \r
-\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsapi.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSAPI=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdate.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsfile.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsmath.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSAPI=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsapi.obj" : $(SOURCE) $(DEP_CPP_JSAPI) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSAPI=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdate.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsfile.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsmath.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSAPI=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsapi.obj" : $(SOURCE) $(DEP_CPP_JSAPI) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsarena.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSARE=\\r
-       ".\jsarena.h"\\r
-       ".\jsbit.h"\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSARE=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsarena.obj" : $(SOURCE) $(DEP_CPP_JSARE) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSARE=\\r
-       ".\jsarena.h"\\r
-       ".\jsbit.h"\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSARE=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsarena.obj" : $(SOURCE) $(DEP_CPP_JSARE) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsarray.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSARR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSARR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsarray.obj" : $(SOURCE) $(DEP_CPP_JSARR) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSARR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSARR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsarray.obj" : $(SOURCE) $(DEP_CPP_JSARR) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsatom.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSATO=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSATO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsatom.obj" : $(SOURCE) $(DEP_CPP_JSATO) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSATO=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSATO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsatom.obj" : $(SOURCE) $(DEP_CPP_JSATO) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsbool.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSBOO=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSBOO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsbool.obj" : $(SOURCE) $(DEP_CPP_JSBOO) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSBOO=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSBOO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsbool.obj" : $(SOURCE) $(DEP_CPP_JSBOO) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jscntxt.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSCNT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSCNT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jscntxt.obj" : $(SOURCE) $(DEP_CPP_JSCNT) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSCNT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSCNT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jscntxt.obj" : $(SOURCE) $(DEP_CPP_JSCNT) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsdate.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSDAT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdate.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\prmjtime.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDAT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdate.obj" : $(SOURCE) $(DEP_CPP_JSDAT) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSDAT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdate.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\prmjtime.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDAT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdate.obj" : $(SOURCE) $(DEP_CPP_JSDAT) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsdbgapi.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSDBG=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDBG=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdbgapi.obj" : $(SOURCE) $(DEP_CPP_JSDBG) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSDBG=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDBG=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdbgapi.obj" : $(SOURCE) $(DEP_CPP_JSDBG) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsdhash.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSDHA=\\r
-       ".\jsbit.h"\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdhash.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDHA=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdhash.obj" : $(SOURCE) $(DEP_CPP_JSDHA) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSDHA=\\r
-       ".\jsbit.h"\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdhash.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDHA=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdhash.obj" : $(SOURCE) $(DEP_CPP_JSDHA) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsdtoa.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSDTO=\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDTO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdtoa.obj" : $(SOURCE) $(DEP_CPP_JSDTO) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSDTO=\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSDTO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsdtoa.obj" : $(SOURCE) $(DEP_CPP_JSDTO) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsemit.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSEMI=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSEMI=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsemit.obj" : $(SOURCE) $(DEP_CPP_JSEMI) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSEMI=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSEMI=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsemit.obj" : $(SOURCE) $(DEP_CPP_JSEMI) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsexn.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSEXN=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSEXN=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsexn.obj" : $(SOURCE) $(DEP_CPP_JSEXN) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSEXN=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSEXN=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsexn.obj" : $(SOURCE) $(DEP_CPP_JSEXN) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsfun.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSFUN=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSFUN=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsfun.obj" : $(SOURCE) $(DEP_CPP_JSFUN) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSFUN=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSFUN=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsfun.obj" : $(SOURCE) $(DEP_CPP_JSFUN) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsgc.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSGC_=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSGC_=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsgc.obj" : $(SOURCE) $(DEP_CPP_JSGC_) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSGC_=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSGC_=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsgc.obj" : $(SOURCE) $(DEP_CPP_JSGC_) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jshash.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSHAS=\\r
-       ".\jsbit.h"\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jshash.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSHAS=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jshash.obj" : $(SOURCE) $(DEP_CPP_JSHAS) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSHAS=\\r
-       ".\jsbit.h"\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jshash.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSHAS=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jshash.obj" : $(SOURCE) $(DEP_CPP_JSHAS) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsinterp.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSINT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSINT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsinterp.obj" : $(SOURCE) $(DEP_CPP_JSINT) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSINT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSINT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsinterp.obj" : $(SOURCE) $(DEP_CPP_JSINT) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jslock.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSLOC=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSLOC=\\r
-       ".\jsautocfg.h"\\r
-       ".\pratom.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       ".\prthread.h"\\r
-       \r
-\r
-"$(INTDIR)\jslock.obj" : $(SOURCE) $(DEP_CPP_JSLOC) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSLOC=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSLOC=\\r
-       ".\jsautocfg.h"\\r
-       ".\pratom.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       ".\prthread.h"\\r
-       \r
-\r
-"$(INTDIR)\jslock.obj" : $(SOURCE) $(DEP_CPP_JSLOC) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jslog2.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSLOG=\\r
-       ".\jsbit.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSLOG=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jslog2.obj" : $(SOURCE) $(DEP_CPP_JSLOG) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSLOG=\\r
-       ".\jsbit.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSLOG=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jslog2.obj" : $(SOURCE) $(DEP_CPP_JSLOG) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jslong.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSLON=\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSLON=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jslong.obj" : $(SOURCE) $(DEP_CPP_JSLON) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSLON=\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jstypes.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSLON=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jslong.obj" : $(SOURCE) $(DEP_CPP_JSLON) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsmath.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSMAT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslibmath.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsmath.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\prmjtime.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSMAT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsmath.obj" : $(SOURCE) $(DEP_CPP_JSMAT) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSMAT=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslibmath.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsmath.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\prmjtime.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSMAT=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsmath.obj" : $(SOURCE) $(DEP_CPP_JSMAT) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsnum.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSNUM=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSNUM=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsnum.obj" : $(SOURCE) $(DEP_CPP_JSNUM) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSNUM=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSNUM=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsnum.obj" : $(SOURCE) $(DEP_CPP_JSNUM) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsobj.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSOBJ=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSOBJ=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsobj.obj" : $(SOURCE) $(DEP_CPP_JSOBJ) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSOBJ=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSOBJ=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsobj.obj" : $(SOURCE) $(DEP_CPP_JSOBJ) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsopcode.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSOPC=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSOPC=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsopcode.obj" : $(SOURCE) $(DEP_CPP_JSOPC) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSOPC=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSOPC=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsopcode.obj" : $(SOURCE) $(DEP_CPP_JSOPC) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsparse.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSPAR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSPAR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsparse.obj" : $(SOURCE) $(DEP_CPP_JSPAR) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSPAR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSPAR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsparse.obj" : $(SOURCE) $(DEP_CPP_JSPAR) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsprf.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSPRF=\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSPRF=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsprf.obj" : $(SOURCE) $(DEP_CPP_JSPRF) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSPRF=\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSPRF=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsprf.obj" : $(SOURCE) $(DEP_CPP_JSPRF) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsregexp.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSREG=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSREG=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsregexp.obj" : $(SOURCE) $(DEP_CPP_JSREG) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSREG=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSREG=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsregexp.obj" : $(SOURCE) $(DEP_CPP_JSREG) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsscan.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSSCA=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSCA=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsscan.obj" : $(SOURCE) $(DEP_CPP_JSSCA) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSSCA=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdtoa.h"\\r
-       ".\jsexn.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSCA=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsscan.obj" : $(SOURCE) $(DEP_CPP_JSSCA) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsscope.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSSCO=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSCO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsscope.obj" : $(SOURCE) $(DEP_CPP_JSSCO) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSSCO=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSCO=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsscope.obj" : $(SOURCE) $(DEP_CPP_JSSCO) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsscript.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSSCR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSCR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsscript.obj" : $(SOURCE) $(DEP_CPP_JSSCR) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSSCR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSCR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsscript.obj" : $(SOURCE) $(DEP_CPP_JSSCR) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsstr.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSSTR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSTR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsstr.obj" : $(SOURCE) $(DEP_CPP_JSSTR) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSSTR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsarray.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsbool.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsnum.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSSTR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsstr.obj" : $(SOURCE) $(DEP_CPP_JSSTR) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsutil.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSUTI=\\r
-       ".\jscpucfg.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSUTI=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsutil.obj" : $(SOURCE) $(DEP_CPP_JSUTI) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSUTI=\\r
-       ".\jscpucfg.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSUTI=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\jsutil.obj" : $(SOURCE) $(DEP_CPP_JSUTI) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\jsxdrapi.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_JSXDR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSXDR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsxdrapi.obj" : $(SOURCE) $(DEP_CPP_JSXDR) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_JSXDR=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       ".\jsxdrapi.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JSXDR=\\r
-       ".\jsautocfg.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\jsxdrapi.obj" : $(SOURCE) $(DEP_CPP_JSXDR) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\prmjtime.c\r
-\r
-!IF  "$(CFG)" == "js - Win32 Release"\r
-\r
-DEP_CPP_PRMJT=\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jstypes.h"\\r
-       ".\prmjtime.h"\\r
-       {$(INCLUDE)}"\sys\TIMEB.H"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_PRMJT=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\prmjtime.obj" : $(SOURCE) $(DEP_CPP_PRMJT) "$(INTDIR)"\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-DEP_CPP_PRMJT=\\r
-       ".\jscompat.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jslong.h"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsprf.h"\\r
-       ".\jstypes.h"\\r
-       ".\prmjtime.h"\\r
-       {$(INCLUDE)}"\sys\TIMEB.H"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_PRMJT=\\r
-       ".\jsautocfg.h"\\r
-       \r
-\r
-"$(INTDIR)\prmjtime.obj" : $(SOURCE) $(DEP_CPP_PRMJT) "$(INTDIR)"\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Project Dependency\r
-\r
-# Project_Dep_Name "fdlibm"\r
-\r
-!IF  "$(CFG)" == "js - Win32 Debug"\r
-\r
-"fdlibm - Win32 Debug" : \r
-   $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="fdlibm - Win32 Debug" \r
-\r
-!ELSEIF  "$(CFG)" == "js - Win32 Release"\r
-\r
-"fdlibm - Win32 Release" : \r
-   $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="fdlibm - Win32 Release" \r
-\r
-!ENDIF \r
-\r
-# End Project Dependency\r
-# End Target\r
-################################################################################\r
-# Begin Target\r
-\r
-# Name "jsshell - Win32 Release"\r
-# Name "jsshell - Win32 Debug"\r
-\r
-!IF  "$(CFG)" == "jsshell - Win32 Release"\r
-\r
-!ELSEIF  "$(CFG)" == "jsshell - Win32 Debug"\r
-\r
-!ENDIF \r
-\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\js.c\r
-DEP_CPP_JS_C42=\\r
-       ".\js.msg"\\r
-       ".\jsapi.h"\\r
-       ".\jsarena.h"\\r
-       ".\jsatom.h"\\r
-       ".\jsclist.h"\\r
-       ".\jscntxt.h"\\r
-       ".\jscompat.h"\\r
-       ".\jsconfig.h"\\r
-       ".\jscpucfg.h"\\r
-       ".\jsdbgapi.h"\\r
-       ".\jsemit.h"\\r
-       ".\jsfun.h"\\r
-       ".\jsgc.h"\\r
-       ".\jshash.h"\\r
-       ".\jsinterp.h"\\r
-       ".\jslock.h"\\r
-       ".\jslong.h"\\r
-       ".\jsobj.h"\\r
-       ".\jsopcode.h"\\r
-       ".\jsopcode.tbl"\\r
-       ".\jsosdep.h"\\r
-       ".\jsotypes.h"\\r
-       ".\jsparse.h"\\r
-       ".\jsprf.h"\\r
-       ".\jsprvtd.h"\\r
-       ".\jspubtd.h"\\r
-       ".\jsregexp.h"\\r
-       ".\jsscan.h"\\r
-       ".\jsscope.h"\\r
-       ".\jsscript.h"\\r
-       ".\jsshell.msg"\\r
-       ".\jsstddef.h"\\r
-       ".\jsstr.h"\\r
-       ".\jstypes.h"\\r
-       ".\jsutil.h"\\r
-       {$(INCLUDE)}"\sys\types.h"\\r
-       \r
-NODEP_CPP_JS_C42=\\r
-       ".\jsautocfg.h"\\r
-       ".\jsdb.h"\\r
-       ".\jsdebug.h"\\r
-       ".\jsdjava.h"\\r
-       ".\jsjava.h"\\r
-       ".\jsperl.h"\\r
-       ".\prcvar.h"\\r
-       ".\prlock.h"\\r
-       \r
-\r
-"$(INTDIR)\js.obj" : $(SOURCE) $(DEP_CPP_JS_C42) "$(INTDIR)"\r
-\r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Project Dependency\r
-\r
-# Project_Dep_Name "js"\r
-\r
-!IF  "$(CFG)" == "jsshell - Win32 Release"\r
-\r
-"js - Win32 Release" : \r
-   $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="js - Win32 Release" \r
-\r
-!ELSEIF  "$(CFG)" == "jsshell - Win32 Debug"\r
-\r
-"js - Win32 Debug" : \r
-   $(MAKE) /$(MAKEFLAGS) /F ".\js.mak" CFG="js - Win32 Debug" \r
-\r
-!ENDIF \r
-\r
-# End Project Dependency\r
-# End Target\r
-################################################################################\r
-# Begin Target\r
-\r
-# Name "fdlibm - Win32 Release"\r
-# Name "fdlibm - Win32 Debug"\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-!ENDIF \r
-\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\w_atan2.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_W_ATA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_atan2.obj" : $(SOURCE) $(DEP_CPP_W_ATA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_W_ATA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_atan2.obj" : $(SOURCE) $(DEP_CPP_W_ATA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_copysign.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_COP=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_copysign.obj" : $(SOURCE) $(DEP_CPP_S_COP) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_COP=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_copysign.obj" : $(SOURCE) $(DEP_CPP_S_COP) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\w_pow.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_W_POW=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_pow.obj" : $(SOURCE) $(DEP_CPP_W_POW) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_W_POW=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_pow.obj" : $(SOURCE) $(DEP_CPP_W_POW) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\e_pow.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_E_POW=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_pow.obj" : $(SOURCE) $(DEP_CPP_E_POW) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_E_POW=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_pow.obj" : $(SOURCE) $(DEP_CPP_E_POW) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\k_standard.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_K_STA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\k_standard.obj" : $(SOURCE) $(DEP_CPP_K_STA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_K_STA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\k_standard.obj" : $(SOURCE) $(DEP_CPP_K_STA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\e_atan2.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_E_ATA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_atan2.obj" : $(SOURCE) $(DEP_CPP_E_ATA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_E_ATA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_atan2.obj" : $(SOURCE) $(DEP_CPP_E_ATA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_isnan.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_ISN=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_isnan.obj" : $(SOURCE) $(DEP_CPP_S_ISN) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_ISN=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_isnan.obj" : $(SOURCE) $(DEP_CPP_S_ISN) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_fabs.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_FAB=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_fabs.obj" : $(SOURCE) $(DEP_CPP_S_FAB) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_FAB=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_fabs.obj" : $(SOURCE) $(DEP_CPP_S_FAB) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\w_sqrt.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_W_SQR=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_sqrt.obj" : $(SOURCE) $(DEP_CPP_W_SQR) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_W_SQR=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\w_sqrt.obj" : $(SOURCE) $(DEP_CPP_W_SQR) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_scalbn.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_SCA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_scalbn.obj" : $(SOURCE) $(DEP_CPP_S_SCA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_SCA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_scalbn.obj" : $(SOURCE) $(DEP_CPP_S_SCA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\e_sqrt.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_E_SQR=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_sqrt.obj" : $(SOURCE) $(DEP_CPP_E_SQR) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_E_SQR=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\e_sqrt.obj" : $(SOURCE) $(DEP_CPP_E_SQR) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_rint.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_RIN=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_rint.obj" : $(SOURCE) $(DEP_CPP_S_RIN) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_RIN=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_rint.obj" : $(SOURCE) $(DEP_CPP_S_RIN) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_atan.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_ATA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_atan.obj" : $(SOURCE) $(DEP_CPP_S_ATA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_ATA=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_atan.obj" : $(SOURCE) $(DEP_CPP_S_ATA) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_finite.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_FIN=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_finite.obj" : $(SOURCE) $(DEP_CPP_S_FIN) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_FIN=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_finite.obj" : $(SOURCE) $(DEP_CPP_S_FIN) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-################################################################################\r
-# Begin Source File\r
-\r
-SOURCE=.\fdlibm\s_matherr.c\r
-\r
-!IF  "$(CFG)" == "fdlibm - Win32 Release"\r
-\r
-DEP_CPP_S_MAT=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_matherr.obj" : $(SOURCE) $(DEP_CPP_S_MAT) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ELSEIF  "$(CFG)" == "fdlibm - Win32 Debug"\r
-\r
-DEP_CPP_S_MAT=\\r
-       ".\fdlibm\fdlibm.h"\\r
-       \r
-\r
-"$(INTDIR)\s_matherr.obj" : $(SOURCE) $(DEP_CPP_S_MAT) "$(INTDIR)"\r
-   $(CPP) $(CPP_PROJ) $(SOURCE)\r
-\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-# End Target\r
-# End Project\r
-################################################################################\r
index dc6c534f7cce89dbfc749fe5d1ba06a3ef0549d7..5df1ead9e23bf7a9905f6f2463230aab0fc33a4a 100644 (file)
@@ -224,7 +224,7 @@ MSG_DEF(JSMSG_UNTERMINATED_REGEXP,    141, 0, JSEXN_SYNTAXERR, "unterminated reg
 MSG_DEF(JSMSG_BAD_REGEXP_FLAG,        142, 0, JSEXN_SYNTAXERR, "invalid flag after regular expression")
 MSG_DEF(JSMSG_SHARPVAR_TOO_BIG,       143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number")
 MSG_DEF(JSMSG_ILLEGAL_CHARACTER,      144, 0, JSEXN_SYNTAXERR, "illegal character")
-MSG_DEF(JSMSG_BAD_OCTAL,              145, 1, JSEXN_NONE, "{0} is not a legal ECMA-262 octal constant")
+MSG_DEF(JSMSG_BAD_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")
@@ -249,3 +249,42 @@ MSG_DEF(JSMSG_RESERVED_SLOT_RANGE,    166, 0, JSEXN_RANGEERR, "reserved slot ind
 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")
index 5b7200a49075b89333aa148d0634511405b4293b..344fc24690ad3413d68181e4522ff44f554e58b3 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
 #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) (ap)
+#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
 #else
 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
 #endif
@@ -242,19 +247,10 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
             *va_arg(ap, JSObject **) = obj;
             break;
           case 'f':
-            /*
-             * Don't convert a cloned function object to its shared private
-             * data, then follow fun->object back to the clone-parent.
-             */
-            if (JSVAL_IS_FUNCTION(cx, *sp)) {
-                fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(*sp));
-            } else {
-                fun = js_ValueToFunction(cx, sp, 0);
-                if (!fun)
-                    return JS_FALSE;
-                *sp = OBJECT_TO_JSVAL(fun->object);
-            }
-            *va_arg(ap, JSFunction **) = fun;
+            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;
@@ -456,7 +452,6 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
 {
     JSBool ok, b;
     JSObject *obj;
-    JSFunction *fun;
     JSString *str;
     jsdouble d, *dp;
 
@@ -472,19 +467,9 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
             *vp = OBJECT_TO_JSVAL(obj);
         break;
       case JSTYPE_FUNCTION:
-        /*
-         * Don't convert a cloned function object to its shared private data,
-         * then follow fun->object back to the clone-parent.
-         */
-        if (JSVAL_IS_FUNCTION(cx, v)) {
-            ok = JS_TRUE;
-            *vp = v;
-        } else {
-            fun = js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
-            ok = (fun != NULL);
-            if (ok)
-                *vp = OBJECT_TO_JSVAL(fun->object);
-        }
+        *vp = v;
+        obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
+        ok = (obj != NULL);
         break;
       case JSTYPE_STRING:
         str = js_ValueToString(cx, v);
@@ -495,7 +480,7 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
       case JSTYPE_NUMBER:
         ok = js_ValueToNumber(cx, v, &d);
         if (ok) {
-            dp = js_NewDouble(cx, d);
+            dp = js_NewDouble(cx, d, 0);
             ok = (dp != NULL);
             if (ok)
                 *vp = DOUBLE_TO_JSVAL(dp);
@@ -598,27 +583,42 @@ JS_TypeOfValue(JSContext *cx, jsval v)
 
     CHECK_REQUEST(cx);
     if (JSVAL_IS_OBJECT(v)) {
-        /* XXX JSVAL_IS_OBJECT(v) is true for null too! Can we change ECMA? */
+        type = JSTYPE_OBJECT;           /* XXXbe JSTYPE_NULL for JS2 */
         obj = JSVAL_TO_OBJECT(v);
-        if (obj &&
-            (ops = obj->map->ops,
-             ops == &js_ObjectOps
-             ? (clasp = OBJ_GET_CLASS(cx, obj),
-                clasp->call || clasp == &js_FunctionClass)
-             : ops->call != NULL)) {
-            type = JSTYPE_FUNCTION;
-        } else {
+        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) {
-                /* XXX suppress errors/exceptions */
-                OBJ_GET_PROPERTY(cx, obj,
-                                 (jsid)cx->runtime->atomState.callAtom,
-                                 &v);
-                if (JSVAL_IS_FUNCTION(cx, v))
-                    return JSTYPE_FUNCTION;
-            }
+                    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
-            type = JSTYPE_OBJECT;
+                }
+            }
         }
     } else if (JSVAL_IS_NUMBER(v)) {
         type = JSTYPE_NUMBER;
@@ -687,7 +687,9 @@ JS_NewRuntime(uint32 maxbytes)
     rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
     if (!rt->requestDone)
         goto bad;
-    js_SetupLocks(8, 16);       /* this is asymmetric with JS_ShutDown. */
+    /* this is asymmetric with JS_ShutDown: */
+    if (!js_SetupLocks(8, 16))
+        goto bad;
     rt->rtLock = JS_NEW_LOCK();
     if (!rt->rtLock)
         goto bad;
@@ -731,6 +733,7 @@ JS_DestroyRuntime(JSRuntime *rt)
     }
 #endif
 
+    js_FreeRuntimeScriptState(rt);
     js_FinishAtomState(&rt->atomState);
     js_FinishGC(rt);
 #ifdef JS_THREADSAFE
@@ -968,7 +971,7 @@ JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
 JS_PUBLIC_API(JSVersion)
 JS_GetVersion(JSContext *cx)
 {
-    return cx->version;
+    return cx->version & JSVERSION_MASK;
 }
 
 JS_PUBLIC_API(JSVersion)
@@ -976,22 +979,15 @@ JS_SetVersion(JSContext *cx, JSVersion version)
 {
     JSVersion oldVersion;
 
-    oldVersion = cx->version;
+    JS_ASSERT(version != JSVERSION_UNKNOWN);
+    JS_ASSERT((version & ~JSVERSION_MASK) == 0);
+
+    oldVersion = cx->version & JSVERSION_MASK;
     if (version == oldVersion)
         return oldVersion;
 
-    cx->version = version;
-
-#if !JS_BUG_FALLIBLE_EQOPS
-    if (cx->version == JSVERSION_1_2) {
-        cx->jsop_eq = JSOP_NEW_EQ;
-        cx->jsop_ne = JSOP_NEW_NE;
-    } else {
-        cx->jsop_eq = JSOP_EQ;
-        cx->jsop_ne = JSOP_NE;
-    }
-#endif /* !JS_BUG_FALLIBLE_EQOPS */
-
+    cx->version = (cx->version & ~JSVERSION_MASK) | version;
+    js_OnVersionChange(cx);
     return oldVersion;
 }
 
@@ -1006,7 +1002,8 @@ static struct v2smap {
     {JSVERSION_1_4,     "1.4"},
     {JSVERSION_ECMA_3,  "ECMAv3"},
     {JSVERSION_1_5,     "1.5"},
-    {JSVERSION_DEFAULT, "default"},
+    {JSVERSION_1_6,     "1.6"},
+    {JSVERSION_DEFAULT, js_default_str},
     {JSVERSION_UNKNOWN, NULL},          /* must be last, NULL is sentinel */
 };
 
@@ -1038,11 +1035,20 @@ 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;
 }
 
@@ -1051,13 +1057,14 @@ 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.5 2004-09-24";
+    return "JavaScript-C 1.6 2006-11-19";
 }
 
 
@@ -1071,6 +1078,9 @@ JS_PUBLIC_API(void)
 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
 {
     cx->globalObject = obj;
+#if JS_HAS_XML_SUPPORT
+    cx->xmlSettingFlags = 0;
+#endif
 }
 
 static JSObject *
@@ -1085,7 +1095,7 @@ InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
 
     /* If cx has no global object, use obj so prototypes can be found. */
     if (!cx->globalObject)
-        cx->globalObject = obj;
+        JS_SetGlobalObject(cx, obj);
 
     /* Record Function and Object in cx->resolvingTable, if we are resolving. */
     table = cx->resolvingTable;
@@ -1093,13 +1103,13 @@ InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
     if (resolving) {
         rt = cx->runtime;
         key.obj = obj;
-        key.id = (jsid) rt->atomState.FunctionAtom;
+        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 = (jsid) rt->atomState.ObjectAtom;
+            key.id = ATOM_TO_JSID(rt->atomState.ObjectAtom);
             entry = (JSResolvingEntry *)
                     JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
         }
@@ -1145,8 +1155,8 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
 {
     /* Define a top-level property 'undefined' with the undefined value. */
     JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
-    if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
-                             JSPROP_PERMANENT, NULL)) {
+    if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
+                             NULL, NULL, JSPROP_PERMANENT, NULL)) {
         return JS_FALSE;
     }
 }
@@ -1174,8 +1184,11 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
 #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, JS_TRUE) &&
+           js_InitFileClass(cx, obj) &&
 #endif
            js_InitDateClass(cx, obj);
 }
@@ -1210,6 +1223,14 @@ static struct {
 #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}
 };
@@ -1282,6 +1303,13 @@ static JSStdName standard_class_names[] = {
     {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}
 };
 
@@ -1337,12 +1365,12 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
     rt = cx->runtime;
 
 #if JS_HAS_UNDEFINED
-    /* See if we're resolving 'undefined', and define it if so. */
+    /* 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, (jsid)atom, JSVAL_VOID, NULL, NULL,
-                                   JSPROP_PERMANENT, NULL);
+        return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
+                                   NULL, NULL, JSPROP_PERMANENT, NULL);
     }
 #endif
 
@@ -1395,17 +1423,10 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
 }
 
 static JSBool
-HasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom, JSBool *ownp)
+AlreadyHasOwnProperty(JSObject *obj, JSAtom *atom)
 {
-    JSObject *pobj;
-    JSProperty *prop;
-
-    if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
-        return JS_FALSE;
-    if (prop)
-        OBJ_DROP_PROPERTY(cx, pobj, prop);
-    *ownp = (pobj == obj && prop);
-    return JS_TRUE;
+    JS_ASSERT(OBJ_IS_NATIVE(obj));
+    return SCOPE_GET_PROPERTY(OBJ_SCOPE(obj), ATOM_TO_JSID(atom)) != NULL;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -1413,20 +1434,17 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
 {
     JSRuntime *rt;
     JSAtom *atom;
-    JSBool found;
     uintN i;
 
     CHECK_REQUEST(cx);
     rt = cx->runtime;
 
 #if JS_HAS_UNDEFINED
-    /* See if we need to bind 'undefined' and define it if so. */
+    /* Check whether we need to bind 'undefined' and define it if so. */
     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
-    if (!HasOwnProperty(cx, obj, atom, &found))
-        return JS_FALSE;
-    if (!found &&
-        !OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
-                            JSPROP_PERMANENT, NULL)) {
+    if (!AlreadyHasOwnProperty(obj, atom) &&
+        !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
+                             NULL, NULL, JSPROP_PERMANENT, NULL)) {
         return JS_FALSE;
     }
 #endif
@@ -1434,15 +1452,106 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
     /* Initialize any classes that have not been resolved yet. */
     for (i = 0; standard_class_atoms[i].init; i++) {
         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
-        if (!HasOwnProperty(cx, obj, atom, &found))
-            return JS_FALSE;
-        if (!found && !standard_class_atoms[i].init(cx, obj))
+        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
 
@@ -1500,7 +1609,7 @@ JS_PUBLIC_API(jsdouble *)
 JS_NewDouble(JSContext *cx, jsdouble d)
 {
     CHECK_REQUEST(cx);
-    return js_NewDouble(cx, d);
+    return js_NewDouble(cx, d, 0);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -1559,6 +1668,7 @@ JS_ClearNewbornRoots(JSContext *cx)
     for (i = 0; i < GCX_NTYPES; i++)
         cx->newborn[i] = NULL;
     cx->lastAtom = NULL;
+    cx->lastInternalResult = JSVAL_NULL;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -1723,6 +1833,9 @@ JS_GC(JSContext *cx)
 JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext *cx)
 {
+#ifdef WAY_TOO_MUCH_GC
+    JS_GC(cx);
+#else
     JSRuntime *rt;
     uint32 bytes, lastBytes;
 
@@ -1730,7 +1843,7 @@ JS_MaybeGC(JSContext *cx)
     bytes = rt->gcBytes;
     lastBytes = rt->gcLastBytes;
     if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) ||
-        rt->gcMallocBytes > rt->gcMaxBytes) {
+        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
@@ -1738,6 +1851,7 @@ JS_MaybeGC(JSContext *cx)
          */
         JS_GC(cx);
     }
+#endif
 }
 
 JS_PUBLIC_API(JSGCCallback)
@@ -1763,6 +1877,19 @@ JS_IsAboutToBeFinalized(JSContext *cx, void *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)
 {
@@ -1783,7 +1910,7 @@ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
     CHECK_REQUEST(cx);
     JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
 
-    str = (JSString *) js_AllocGCThing(cx, (uintN) type);
+    str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
     if (!str)
         return NULL;
     str->length = length;
@@ -1802,32 +1929,9 @@ JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
     return -1;
 }
 
-#ifdef DEBUG
-/* FIXME: 242518 static */ void
-CheckStackGrowthDirection(int *dummy1addr, jsuword limitAddr)
-{
-    int dummy2;
-
-#if JS_STACK_GROWTH_DIRECTION > 0
-    JS_ASSERT(dummy1addr < &dummy2);
-    JS_ASSERT((jsuword)&dummy2 < limitAddr);
-#else
-    /* Stack grows downward, the common case on modern architectures. */
-    JS_ASSERT(&dummy2 < dummy1addr);
-    JS_ASSERT(limitAddr < (jsuword)&dummy2);
-#endif
-}
-#endif
-
 JS_PUBLIC_API(void)
 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
 {
-#ifdef DEBUG
-    int dummy1;
-
-    CheckStackGrowthDirection(&dummy1, limitAddr);
-#endif
-
 #if JS_STACK_GROWTH_DIRECTION > 0
     if (limitAddr == 0)
         limitAddr = (jsuword)-1;
@@ -1855,7 +1959,7 @@ JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
         atom = js_ValueToStringAtom(cx, v);
         if (!atom)
             return JS_FALSE;
-        *idp = (jsid)atom;
+        *idp = ATOM_TO_JSID(atom);
     }
     return JS_TRUE;
 }
@@ -1893,7 +1997,8 @@ JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
     if (type == JSTYPE_STRING)
         return JS_TRUE;
 #endif
-    return js_TryValueOf(cx, obj, type, vp);
+    js_TryValueOf(cx, obj, type, vp);
+    return JS_TRUE;
 }
 
 JS_PUBLIC_API(void)
@@ -1909,9 +2014,10 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
 {
     JSAtom *atom;
     JSObject *proto, *ctor;
+    JSTempValueRooter tvr;
+    jsval cval, rval;
     JSBool named;
     JSFunction *fun;
-    jsval junk;
 
     CHECK_REQUEST(cx);
     atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
@@ -1923,9 +2029,13 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
     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, (jsid)atom, OBJECT_TO_JSVAL(proto),
+        named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
+                                    OBJECT_TO_JSVAL(proto),
                                     NULL, NULL, 0, NULL);
         if (!named)
             goto bad;
@@ -1944,8 +2054,22 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
          */
         fun->clasp = clasp;
 
-        /* Connect constructor and prototype by named properties. */
+        /*
+         * 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;
@@ -1968,13 +2092,16 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
         (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, (jsid)atom, &junk);
-    cx->newborn[GCX_OBJECT] = NULL;
-    return NULL;
+        (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
+    proto = NULL;
+    goto out;
 }
 
 #ifdef JS_THREADSAFE
@@ -2012,6 +2139,12 @@ JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
     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)
 {
@@ -2091,7 +2224,7 @@ JS_GetConstructor(JSContext *cx, JSObject *proto)
 
     CHECK_REQUEST(cx);
     if (!OBJ_GET_PROPERTY(cx, proto,
-                          (jsid)cx->runtime->atomState.constructorAtom,
+                          ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
                           &cval)) {
         return NULL;
     }
@@ -2106,8 +2239,8 @@ JS_GetConstructor(JSContext *cx, JSObject *proto)
 JS_PUBLIC_API(JSBool)
 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
 {
-    JS_ASSERT(((jsid)obj & JSVAL_TAGMASK) == 0);
-    *idp = (jsid) obj | JSVAL_INT;
+    JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
+    *idp = OBJECT_TO_JSID(obj);
     return JS_TRUE;
 }
 
@@ -2211,14 +2344,14 @@ DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
     JSAtom *atom;
 
     if (attrs & JSPROP_INDEX) {
-        id = INT_TO_JSVAL((jsint)name);
+        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 = (jsid)atom;
+        id = ATOM_TO_JSID(atom);
     }
     if (flags != 0 && OBJ_IS_NATIVE(obj)) {
         return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
@@ -2242,12 +2375,12 @@ DefineUCProperty(JSContext *cx, JSObject *obj,
     if (!atom)
         return JS_FALSE;
     if (flags != 0 && OBJ_IS_NATIVE(obj)) {
-        return js_DefineNativeProperty(cx, obj, (jsid)atom, value,
+        return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
                                        getter, setter, attrs, flags, tinyid,
                                        NULL);
     }
-    return OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, value, getter, setter,
-                               attrs, NULL);
+    return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
+                               getter, setter, attrs, NULL);
 }
 
 JS_PUBLIC_API(JSObject *)
@@ -2336,7 +2469,7 @@ LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
     atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, objp, propp);
+    return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
 }
 
 static JSBool
@@ -2349,7 +2482,7 @@ LookupUCProperty(JSContext *cx, JSObject *obj,
     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, objp, propp);
+    return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -2380,7 +2513,7 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
         ok = JS_FALSE;
     } else {
         sprop = (JSScopeProperty *)prop;
-        ok = (js_AddNativeProperty(cx, obj, (jsid)atom,
+        ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
                                    sprop->getter, sprop->setter, sprop->slot,
                                    sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
                                    sprop->shortid)
@@ -2416,7 +2549,8 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
 
 static JSBool
 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
-                      uintN *attrsp, JSBool *foundp)
+                      uintN *attrsp, JSBool *foundp,
+                      JSPropertyOp *getterp, JSPropertyOp *setterp)
 {
     JSObject *obj2;
     JSProperty *prop;
@@ -2424,17 +2558,31 @@ GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
 
     if (!atom)
         return JS_FALSE;
-    if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
+    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, (jsid)atom, prop, attrsp);
+    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;
 }
@@ -2449,7 +2597,7 @@ SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
 
     if (!atom)
         return JS_FALSE;
-    if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
+    if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
         return JS_FALSE;
     if (!prop || obj != obj2) {
         *foundp = JS_FALSE;
@@ -2459,12 +2607,11 @@ SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
     }
 
     *foundp = JS_TRUE;
-    ok = OBJ_SET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
+    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)
@@ -2472,7 +2619,20 @@ JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
     CHECK_REQUEST(cx);
     return GetPropertyAttributes(cx, obj,
                                  js_Atomize(cx, name, strlen(name), 0),
-                                 attrsp, foundp);
+                                 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)
@@ -2530,12 +2690,9 @@ JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
     if (!atom)
         return JS_FALSE;
     ok = OBJ_IS_NATIVE(obj)
-         ? js_LookupPropertyWithFlags(cx, obj, (jsid)atom, flags, &obj2, &prop
-#if defined JS_THREADSAFE && defined DEBUG
-                                      , __FILE__, __LINE__
-#endif
-                                      )
-         : OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop);
+         ? 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;
@@ -2550,7 +2707,39 @@ JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
     atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
+    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)
@@ -2562,7 +2751,7 @@ JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
     atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_SET_PROPERTY(cx, obj, (jsid)atom, vp);
+    return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -2584,7 +2773,7 @@ JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
     atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, rval);
+    return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -2606,7 +2795,20 @@ JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
     CHECK_REQUEST(cx);
     return GetPropertyAttributes(cx, obj,
                     js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
-                    attrsp, foundp);
+                    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)
@@ -2678,7 +2880,7 @@ JS_GetUCProperty(JSContext *cx, JSObject *obj,
     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
+    return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -2692,7 +2894,7 @@ JS_SetUCProperty(JSContext *cx, JSObject *obj,
     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_SET_PROPERTY(cx, obj, (jsid)atom, vp);
+    return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -2706,7 +2908,7 @@ JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     if (!atom)
         return JS_FALSE;
-    return OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, rval);
+    return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
 }
 
 JS_PUBLIC_API(JSObject *)
@@ -2749,7 +2951,7 @@ JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
                  JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
 {
     CHECK_REQUEST(cx);
-    return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(index), value,
+    return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
                                getter, setter, attrs, NULL);
 }
 
@@ -2777,7 +2979,7 @@ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
         return JS_FALSE;
     }
     sprop = (JSScopeProperty *)prop;
-    ok = (js_AddNativeProperty(cx, obj, INT_TO_JSVAL(alias),
+    ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
                                sprop->getter, sprop->setter, sprop->slot,
                                sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
                                sprop->shortid)
@@ -2794,7 +2996,7 @@ JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
     JSProperty *prop;
 
     CHECK_REQUEST(cx);
-    ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSVAL(index), &obj2, &prop);
+    ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
     if (ok) {
         *foundp = (prop != NULL);
         if (prop)
@@ -2811,7 +3013,7 @@ JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
     JSProperty *prop;
 
     CHECK_REQUEST(cx);
-    ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSVAL(index), &obj2, &prop);
+    ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
     if (ok)
         *vp = LookupResult(cx, obj, obj2, prop);
     return ok;
@@ -2821,14 +3023,14 @@ JS_PUBLIC_API(JSBool)
 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
 {
     CHECK_REQUEST(cx);
-    return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSVAL(index), vp);
+    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_JSVAL(index), vp);
+    return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -2844,7 +3046,7 @@ JS_PUBLIC_API(JSBool)
 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
 {
     CHECK_REQUEST(cx);
-    return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSVAL(index), rval);
+    return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
 }
 
 JS_PUBLIC_API(void)
@@ -2891,25 +3093,22 @@ JS_Enumerate(JSContext *cx, JSObject *obj)
     i = 0;
     vector = &ida->vector[0];
     for (;;) {
-        if (i == ida->length) {
-            /* Grow length by factor of 1.5 instead of doubling. */
-            jsint newlen = ida->length + (((jsuint)ida->length + 1) >> 1);
-            ida = js_GrowIdArray(cx, ida, newlen);
-            if (!ida)
-                goto error;
-            vector = &ida->vector[0];
-        }
-
         if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
             goto error;
 
         /* No more jsid's to enumerate ? */
         if (iter_state == JSVAL_NULL)
             break;
+
+        if (i == ida->length) {
+            ida = js_SetIdArrayLength(cx, ida, ida->length * 2);
+            if (!ida)
+                goto error;
+            vector = &ida->vector[0];
+        }
         vector[i++] = id;
     }
-    ida->length = i;
-    return ida;
+    return js_SetIdArrayLength(cx, ida, i);
 
 error:
     if (iter_state != JSVAL_NULL)
@@ -2919,6 +3118,182 @@ error:
     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)
@@ -3011,12 +3386,12 @@ JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
 }
 
 JS_PUBLIC_API(JSObjectPrincipalsFinder)
-JS_SetObjectPrincipalsFinder(JSContext *cx, JSObjectPrincipalsFinder fop)
+JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop)
 {
     JSObjectPrincipalsFinder oldfop;
 
-    oldfop = cx->findObjectPrincipals;
-    cx->findObjectPrincipals = fop;
+    oldfop = rt->findObjectPrincipals;
+    rt->findObjectPrincipals = fop;
     return oldfop;
 }
 
@@ -3075,21 +3450,112 @@ 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++) {
-        fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs,
-                                fs->flags);
+        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;
@@ -3169,7 +3635,7 @@ JS_CompileScript(JSContext *cx, JSObject *obj,
     JSScript *script;
 
     CHECK_REQUEST(cx);
-    chars = js_InflateString(cx, bytes, length);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
@@ -3187,7 +3653,7 @@ JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
     JSScript *script;
 
     CHECK_REQUEST(cx);
-    chars = js_InflateString(cx, bytes, length);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
@@ -3206,6 +3672,24 @@ JS_CompileUCScript(JSContext *cx, JSObject *obj,
                                            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,
@@ -3222,10 +3706,7 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
     if (!ts)
         return NULL;
     script = CompileTokenStream(cx, obj, ts, mark, NULL);
-#if JS_HAS_EXCEPTIONS
-    if (!script && !cx->fp)
-        js_ReportUncaughtException(cx);
-#endif
+    LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
@@ -3241,7 +3722,7 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
     JSErrorReporter older;
 
     CHECK_REQUEST(cx);
-    chars = js_InflateString(cx, bytes, length);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return JS_TRUE;
 
@@ -3255,13 +3736,14 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
     ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
     if (ts) {
         older = JS_SetErrorReporter(cx, NULL);
-        if (!js_ParseTokenStream(cx, obj, ts)) {
+        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 = (ts->flags & TSF_EOF) == 0;
+            result = JS_FALSE;
         }
 
         JS_SetErrorReporter(cx, older);
@@ -3287,10 +3769,7 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
     if (!ts)
         return NULL;
     script = CompileTokenStream(cx, obj, ts, mark, NULL);
-#if JS_HAS_EXCEPTIONS
-    if (!script && !cx->fp)
-        js_ReportUncaughtException(cx);
-#endif
+    LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
@@ -3322,10 +3801,7 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
         JSPRINCIPALS_HOLD(cx, ts->principals);
     }
     script = CompileTokenStream(cx, obj, ts, mark, NULL);
-#if JS_HAS_EXCEPTIONS
-    if (!script && !cx->fp)
-        js_ReportUncaughtException(cx);
-#endif
+    LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
@@ -3369,7 +3845,7 @@ JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
     JSFunction *fun;
 
     CHECK_REQUEST(cx);
-    chars = js_InflateString(cx, bytes, length);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
@@ -3389,7 +3865,7 @@ JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
     JSFunction *fun;
 
     CHECK_REQUEST(cx);
-    chars = js_InflateString(cx, bytes, length);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
@@ -3449,11 +3925,10 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
             argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
             if (!argAtom)
                 break;
-            if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
+            if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
                                       js_GetArgument, js_SetArgument,
                                       SPROP_INVALID_SLOT,
-                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
-                                      JSPROP_SHARED,
+                                      JSPROP_PERMANENT | JSPROP_SHARED,
                                       SPROP_HAS_SHORTID, i)) {
                 break;
             }
@@ -3468,9 +3943,9 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
         goto out;
     }
     if (obj && funAtom) {
-        if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)funAtom,
+        if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
                                  OBJECT_TO_JSVAL(fun->object),
-                                 NULL, NULL, 0, NULL)) {
+                                 NULL, NULL, JSPROP_ENUMERATE, NULL)) {
             return NULL;
         }
     }
@@ -3478,10 +3953,7 @@ out:
     if (ts)
         js_CloseTokenStream(cx, ts);
     JS_ARENA_RELEASE(&cx->tempPool, mark);
-#if JS_HAS_EXCEPTIONS
-    if (!fun && !cx->fp)
-        js_ReportUncaughtException(cx);
-#endif
+    LAST_FRAME_CHECKS(cx, fun);
     return fun;
 }
 
@@ -3549,15 +4021,12 @@ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
 JS_PUBLIC_API(JSBool)
 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
 {
+    JSBool ok;
+
     CHECK_REQUEST(cx);
-    if (!js_Execute(cx, obj, script, NULL, 0, rval)) {
-#if JS_HAS_EXCEPTIONS
-        if (!cx->fp)
-            js_ReportUncaughtException(cx);
-#endif
-        return JS_FALSE;
-    }
-    return JS_TRUE;
+    ok = js_Execute(cx, obj, script, NULL, 0, rval);
+    LAST_FRAME_CHECKS(cx, ok);
+    return ok;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -3593,15 +4062,16 @@ JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateScript(JSContext *cx, JSObject *obj,
-                  const char *bytes, uintN length,
+                  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);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return JS_FALSE;
     ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
@@ -3612,15 +4082,16 @@ JS_EvaluateScript(JSContext *cx, JSObject *obj,
 JS_PUBLIC_API(JSBool)
 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
                                JSPrincipals *principals,
-                               const char *bytes, uintN length,
+                               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);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return JS_FALSE;
     ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
@@ -3660,10 +4131,7 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
     if (!script)
         return JS_FALSE;
     ok = js_Execute(cx, obj, script, NULL, 0, rval);
-#if JS_HAS_EXCEPTIONS
-    if (!ok && !cx->fp)
-        js_ReportUncaughtException(cx);
-#endif
+    LAST_FRAME_CHECKS(cx, ok);
     JS_DestroyScript(cx, script);
     return ok;
 }
@@ -3672,50 +4140,54 @@ JS_PUBLIC_API(JSBool)
 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
                 jsval *argv, jsval *rval)
 {
+    JSBool ok;
+
     CHECK_REQUEST(cx);
-    if (!js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
-                         rval)) {
-#if JS_HAS_EXCEPTIONS
-        if (!cx->fp)
-            js_ReportUncaughtException(cx);
-#endif
-        return JS_FALSE;
-    }
-    return JS_TRUE;
+    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_GetProperty(cx, obj, name, &fval))
-        return JS_FALSE;
-    if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) {
-#if JS_HAS_EXCEPTIONS
-        if (!cx->fp)
-            js_ReportUncaughtException(cx);
+#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;
-    }
-    return JS_TRUE;
+    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);
-    if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) {
-#if JS_HAS_EXCEPTIONS
-        if (!cx->fp)
-            js_ReportUncaughtException(cx);
-#endif
-        return JS_FALSE;
-    }
-    return JS_TRUE;
+    ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
+    LAST_FRAME_CHECKS(cx, ok);
+    return ok;
 }
 
 JS_PUBLIC_API(JSBranchCallback)
@@ -3769,15 +4241,16 @@ 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, length);
+    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, length, 0);
+    str = js_NewString(cx, chars, charsLength, 0);
     if (!str) {
         JS_free(cx, chars);
         return NULL;
@@ -3796,7 +4269,7 @@ JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
     JSString *str;
 
     CHECK_REQUEST(cx);
-    js = js_InflateString(cx, s, n);
+    js = js_InflateString(cx, s, &n);
     if (!js)
         return NULL;
     str = js_NewString(cx, js, n, 0);
@@ -3816,7 +4289,7 @@ JS_NewStringCopyZ(JSContext *cx, const char *s)
     if (!s)
         return cx->runtime->emptyString;
     n = strlen(s);
-    js = js_InflateString(cx, s, n);
+    js = js_InflateString(cx, s, &n);
     if (!js)
         return NULL;
     str = js_NewString(cx, js, n, 0);
@@ -3960,6 +4433,30 @@ JS_MakeStringImmutable(JSContext *cx, JSString *str)
     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)
@@ -4067,7 +4564,7 @@ JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
     JSObject *obj;
 
     CHECK_REQUEST(cx);
-    chars = js_InflateString(cx, bytes, length);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
@@ -4195,8 +4692,21 @@ JS_PUBLIC_API(JSBool)
 JS_ReportPendingException(JSContext *cx)
 {
 #if JS_HAS_EXCEPTIONS
+    JSBool save, ok;
+
     CHECK_REQUEST(cx);
-    return js_ReportUncaughtException(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
@@ -4259,7 +4769,7 @@ JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
 JS_PUBLIC_API(JSErrorReport *)
 JS_ErrorFromException(JSContext *cx, jsval v)
 {
-#if JS_HAS_EXCEPTIONS
+#if JS_HAS_ERROR_EXCEPTIONS
     CHECK_REQUEST(cx);
     return js_ErrorFromException(cx, v);
 #else
@@ -4267,6 +4777,13 @@ JS_ErrorFromException(JSContext *cx, jsval v)
 #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)
index 8f491ffec363fc8b4e124ada0f170f9e49216259..9fe07ac601c590d33f7d8b6723773577fb8d9b84 100644 (file)
@@ -134,6 +134,19 @@ JS_BEGIN_EXTERN_C
 #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).
@@ -446,6 +459,17 @@ JS_StringToVersion(const char *string);
                                                    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);
@@ -495,6 +519,15 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
 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);
 
@@ -706,8 +739,16 @@ 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 an external string finalizer, one created by JS_NewExternalString (see
+ * 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).
  *
@@ -792,6 +833,18 @@ struct JSClass {
     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 */
@@ -801,6 +854,9 @@ struct JSClass {
                                                    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
@@ -816,8 +872,15 @@ struct JSClass {
                                           >> 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 {
@@ -850,6 +913,15 @@ struct JSObjectOps {
     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
@@ -878,6 +950,16 @@ 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) ?...:...' */
@@ -948,6 +1030,9 @@ JS_GetClass(JSObject *obj);
 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);
 
@@ -1019,6 +1104,18 @@ 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.
  *
@@ -1052,6 +1149,10 @@ JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
 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);
 
@@ -1079,6 +1180,18 @@ 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.
  *
@@ -1169,6 +1282,22 @@ 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);
@@ -1189,12 +1318,16 @@ JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v);
  */
 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, struct JSPrincipals *);
+
+    void   (* JS_DLL_CALLBACK destroy)(JSContext *cx, JSPrincipals *);
+    JSBool (* JS_DLL_CALLBACK subsume)(JSPrincipals *, JSPrincipals *);
 };
 
 #ifdef JS_THREADSAFE
@@ -1219,7 +1352,7 @@ extern JS_PUBLIC_API(JSPrincipalsTranscoder)
 JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px);
 
 extern JS_PUBLIC_API(JSObjectPrincipalsFinder)
-JS_SetObjectPrincipalsFinder(JSContext *cx, JSObjectPrincipalsFinder fop);
+JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop);
 
 /************************************************************************/
 
@@ -1259,6 +1392,12 @@ JS_GetFunctionId(JSFunction *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
@@ -1625,6 +1764,44 @@ JS_UndependString(JSContext *cx, JSString *str);
 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);
+
 /************************************************************************/
 
 /*
@@ -1813,6 +1990,14 @@ JS_DropExceptionState(JSContext *cx, JSExceptionState *state);
 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
 
 /*
index 2abcacd2b382eabcfa1486d6577c31ae3dbf8c8e..8b2c8a54115017532510b22fb756dd70fbb24557 100644 (file)
@@ -78,11 +78,11 @@ JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, size_t align)
     }
 #endif
     if (align == 0)
-       align = JS_ARENA_DEFAULT_ALIGN;
+        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);
+        JS_ARENA_ALIGN(pool, &pool->first + 1);
     pool->current = &pool->first;
     pool->arenasize = size;
 #ifdef JS_ARENAMETER
@@ -159,27 +159,38 @@ JS_ArenaAllocate(JSArenaPool *pool, size_t nb)
     jsuword extra, hdrsz, gross, sz;
     void *p;
 
-    /* Search pool from current forward till we find or make enough space. */
+    /*
+     * 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 <jk@blackdown.de>, who brought this up in
+     * https://bugzilla.mozilla.org/show_bug.cgi?id=279273.
+     */
     JS_ASSERT((nb & pool->mask) == 0);
-    for (a = pool->current; a->avail + nb > a->limit; pool->current = a) {
+    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 if nb is not greater than
-                 * arenasize.  Otherwise take any arena big enough, but not by
-                 * more than gross + arenasize.
+                 * 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 (extra
-                    ? sz >= gross && sz <= gross + pool->arenasize
-                    : sz == gross) {
+                if (sz == gross) {
                     *bp = b->next;
                     JS_RELEASE_LOCK(arena_freelist_lock);
                     b->next = NULL;
@@ -193,7 +204,7 @@ JS_ArenaAllocate(JSArenaPool *pool, size_t nb)
             JS_RELEASE_LOCK(arena_freelist_lock);
             b = (JSArena *) malloc(gross);
             if (!b)
-                return 0;
+                return NULL;
             b->next = NULL;
             b->limit = (jsuword)b + gross;
             JS_COUNT_ARENA(pool,++);
@@ -247,6 +258,7 @@ JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr)
     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;
@@ -312,34 +324,34 @@ FreeArenaList(JSArenaPool *pool, JSArena *head, JSBool reallyFree)
     ap = &head->next;
     a = *ap;
     if (!a)
-       return;
+        return;
 
 #ifdef DEBUG
     do {
-       JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
-       a->avail = a->base;
-       JS_CLEAR_UNUSED(a);
+        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);
+        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);
+        /* 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;
+        *ap = arena_freelist;
+        arena_freelist = a;
         JS_RELEASE_LOCK(arena_freelist_lock);
-       head->next = NULL;
+        head->next = NULL;
     }
 
     pool->current = head;
@@ -351,14 +363,14 @@ 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);
+        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);
+        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;
-       }
+            FreeArenaList(pool, a, JS_TRUE);
+            return;
+        }
     }
 }
 
@@ -439,17 +451,17 @@ 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;
-           }
-       }
+        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
 }
@@ -543,9 +555,9 @@ JS_DumpArenaStats(FILE *fp)
             else
                 variance /= nallocs * (nallocs - 1);
             sigma = sqrt(variance);
-       } else {
-           mean = variance = sigma = 0;
-       }
+        } else {
+            mean = variance = sigma = 0;
+        }
 
         fprintf(fp, "\n%s allocation statistics:\n", stats->name);
         fprintf(fp, "              number of arenas: %u\n", stats->narenas);
index e52398a1a822c81bad583801ac64e209b4b70b8d..5370f8f82686bd7ca033881785b6654dd63cddde 100644 (file)
@@ -113,19 +113,30 @@ struct JSArenaPool {
     JS_ARENA_ALLOCATE_CAST(p, void *, pool, nb)
 
 #define JS_ARENA_ALLOCATE_TYPE(p, type, pool)                                 \
-    JS_ARENA_ALLOCATE_CAST(p, type *, pool, sizeof(type))
+    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 <jk@blackdown.de>, 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;                                               \
-        jsuword _q = _p + _nb;                                                \
-        JS_ASSERT(_q >= _p);                                                  \
-        if (_q > _a->limit)                                                   \
+        if ((guard) || _p > _a->limit - _nb)                                  \
             _p = (jsuword)JS_ArenaAllocate(pool, _nb);                        \
         else                                                                  \
-            _a->avail = _q;                                                   \
+            _a->avail = _p + _nb;                                             \
         p = (type) _p;                                                        \
         JS_ArenaCountAllocation(pool, nb);                                    \
     JS_END_MACRO
@@ -138,9 +149,9 @@ struct JSArenaPool {
         JSArena *_a = (pool)->current;                                        \
         if (_a->avail == (jsuword)(p) + JS_ARENA_ALIGN(pool, size)) {         \
             size_t _nb = (size) + (incr);                                     \
-            jsuword _q = (jsuword)(p) + JS_ARENA_ALIGN(pool, _nb);            \
-            if (_q <= _a->limit) {                                            \
-                _a->avail = _q;                                               \
+            _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);              \
index a05a6ee3c0c2854f15b6d3a45aed2b641ed7260c..ef94be4e52a2969d6ae83d42e0e17c4bbc71290d 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
@@ -48,6 +49,7 @@
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
+#include "jsbool.h"
 #include "jscntxt.h"
 #include "jsconfig.h"
 #include "jsfun.h"
@@ -63,7 +65,7 @@
 #define MAXSTR   "4294967295"
 
 /*
- * Determine if the id represents an array index.
+ * 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):
  *
@@ -78,8 +80,8 @@
  * that calling a standard conversion routine might allow strings such as
  * "08" or "4.0" as array indices, which they are not.
  */
-static JSBool
-IdIsIndex(jsid id, jsuint *indexp)
+JSBool
+js_IdIsIndex(jsval id, jsuint *indexp)
 {
     JSString *str;
     jschar *cp;
@@ -93,7 +95,10 @@ IdIsIndex(jsid id, jsuint *indexp)
         return JS_TRUE;
     }
 
-    /* It must be a string. */
+    /* 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)) {
@@ -108,9 +113,8 @@ IdIsIndex(jsid id, jsuint *indexp)
                 cp++;
             }
         }
-        /* Make sure all characters were consumed and that it couldn't
-         * have overflowed.
-         */
+
+        /* Ensure that all characters were consumed and we didn't overflow. */
         if (*cp == 0 &&
              (oldIndex < (MAXINDEX / 10) ||
               (oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
@@ -138,7 +142,7 @@ ValueIsLength(JSContext *cx, jsval v, jsuint *lengthp)
         *lengthp = (jsuint) i;
         return JS_TRUE;
     }
-    
+
     if (!js_ValueToNumber(cx, v, &d)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BAD_ARRAY_LENGTH);
@@ -160,57 +164,94 @@ ValueIsLength(JSContext *cx, jsval v, jsuint *lengthp)
 JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
+    JSTempValueRooter tvr;
     jsid id;
+    JSBool ok;
     jsint i;
-    jsval v;
-
-    id = (jsid) cx->runtime->atomState.lengthAtom;
-    if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
-        return JS_FALSE;
 
-    /* Short-circuit, because js_ValueToECMAUint32 fails when
-     * called during init time.
-     */
-    if (JSVAL_IS_INT(v)) {
-        i = JSVAL_TO_INT(v);
-        /* jsuint cast does ToUint32. */
-        *lengthp = (jsuint)i;
-        return JS_TRUE;
+    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);
+        }
     }
-    return js_ValueToECMAUint32(cx, v, (uint32 *)lengthp);
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return ok;
 }
 
 static JSBool
-IndexToValue(JSContext *cx, jsuint length, jsval *vp)
+IndexToValue(JSContext *cx, jsuint index, jsval *vp)
 {
-    if (length <= JSVAL_INT_MAX) {
-        *vp = INT_TO_JSVAL(length);
+    if (index <= JSVAL_INT_MAX) {
+        *vp = INT_TO_JSVAL(index);
         return JS_TRUE;
     }
-    return js_NewDoubleValue(cx, (jsdouble)length, vp);
+    return js_NewDoubleValue(cx, (jsdouble)index, vp);
 }
 
 static JSBool
-IndexToId(JSContext *cx, jsuint length, jsid *idp)
+IndexToId(JSContext *cx, jsuint index, jsid *idp)
 {
     JSString *str;
     JSAtom *atom;
 
-    if (length <= JSVAL_INT_MAX) {
-        *idp = (jsid) INT_TO_JSVAL(length);
+    if (index <= JSVAL_INT_MAX) {
+        *idp = INT_TO_JSID(index);
     } else {
-        str = js_NumberToString(cx, (jsdouble)length);
+        str = js_NumberToString(cx, (jsdouble)index);
         if (!str)
             return JS_FALSE;
         atom = js_AtomizeString(cx, str, 0);
         if (!atom)
             return JS_FALSE;
-        *idp = (jsid)atom;
+        *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)
 {
@@ -219,7 +260,7 @@ js_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length)
 
     if (!IndexToValue(cx, length, &v))
         return JS_FALSE;
-    id = (jsid) cx->runtime->atomState.lengthAtom;
+    id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     return OBJ_SET_PROPERTY(cx, obj, id, &v);
 }
 
@@ -227,17 +268,19 @@ JSBool
 js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     JSErrorReporter older;
+    JSTempValueRooter tvr;
     jsid id;
     JSBool ok;
-    jsval v;
 
     older = JS_SetErrorReporter(cx, NULL);
-    id = (jsid) cx->runtime->atomState.lengthAtom;
-    ok = OBJ_GET_PROPERTY(cx, obj, id, &v);
+    JS_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)
-        return JS_FALSE;
-    return ValueIsLength(cx, v, lengthp);
+    if (ok)
+        ok = ValueIsLength(cx, tvr.u.value, lengthp);
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return ok;
 }
 
 /*
@@ -278,7 +321,7 @@ array_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     jsuint index, length;
 
-    if (!(IdIsIndex(id, &index)))
+    if (!js_IdIsIndex(id, &index))
         return JS_TRUE;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
@@ -294,7 +337,7 @@ array_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
 {
     jsuint length;
 
-    if (cx->version == JSVERSION_1_2) {
+    if (JS_VERSION_IS_1_2(cx)) {
         if (!js_GetLengthProperty(cx, obj, &length))
             return JS_FALSE;
         switch (type) {
@@ -323,14 +366,20 @@ array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
                jsval *rval, JSBool localeString)
 {
     JSBool ok;
-    jsval v;
     jsuint length, index;
     jschar *chars, *ochars;
     size_t nchars, growth, seplen, tmplen;
     const jschar *sepstr;
     JSString *str;
     JSHashEntry *he;
-    JSObject *obj2;
+    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)
@@ -398,24 +447,28 @@ array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
     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 && (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v))) {
+        if ((!literalize || JS_VERSION_IS_1_2(cx)) &&
+            (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v))) {
             str = cx->runtime->emptyString;
         } else {
             if (localeString) {
-                if (!js_ValueToObject(cx, v, &obj2) ||
-                    !js_TryMethod(cx, obj2,
-                                  cx->runtime->atomState.toLocaleStringAtom,
-                                  0, NULL, &v)) {
-                    str = NULL;
-                } else {
-                    str = js_ValueToString(cx, v);
-                }
+                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);
             }
@@ -426,9 +479,18 @@ array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
         }
 
         /* Allocate 3 + 1 at end for ", ", closing bracket, and zero. */
-        growth = (nchars + (sepstr ? seplen : 0) +
-                  JSSTRING_LENGTH(str) +
-                  3 + 1) * sizeof(jschar);
+        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)
@@ -447,7 +509,6 @@ array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
         }
         sepstr = JSSTRING_CHARS(sep);
 
-        tmplen = JSSTRING_LENGTH(str);
         js_strncpy(&chars[nchars], JSSTRING_CHARS(str), tmplen);
         nchars += tmplen;
     }
@@ -471,6 +532,8 @@ array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
         return ok;
     }
 
+#undef v
+
   make_string:
     if (!chars) {
         JS_ReportOutOfMemory(cx);
@@ -510,7 +573,7 @@ array_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
      * JS1.2 arrays convert to array literals, with a comma followed by a space
      * between each element.
      */
-    literalize = (cx->version == JSVERSION_1_2);
+    literalize = JS_VERSION_IS_1_2(cx);
     return array_join_sub(cx, obj, literalize ? &comma_space : &comma,
                           literalize, rval, JS_FALSE);
 }
@@ -533,6 +596,8 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint length, jsval *vector)
     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]))
@@ -549,7 +614,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector)
 
     if (!IndexToValue(cx, length, &v))
         return JS_FALSE;
-    id = (jsid) cx->runtime->atomState.lengthAtom;
+    id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     if (!OBJ_DEFINE_PROPERTY(cx, obj, id, v,
                              array_length_getter, array_length_setter,
                              JSPROP_PERMANENT,
@@ -585,42 +650,76 @@ array_reverse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 {
     jsuint len, half, i;
     jsid id, id2;
-    jsval v, v2;
+    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))
-            return JS_FALSE;
-        if (!IndexToId(cx, len - i - 1, &id2))
-            return JS_FALSE;
-        if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
-            return JS_FALSE;
-        if (!OBJ_GET_PROPERTY(cx, obj, id2, &v2))
-            return JS_FALSE;
-
-#if JS_HAS_SPARSE_ARRAYS
-        /* This part isn't done yet. */
+            goto bad;
+        if (!PropertyExists(cx, obj, id, &idexists))
+            goto bad;
+        if (idexists && !OBJ_GET_PROPERTY(cx, obj, id, tmproot))
+            goto bad;
 
-        if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
-            return JS_FALSE;
-        if (!prop) {
-            OBJ_DELETE_PROPERTY(cx, obj, id2, &v); /* v is junk. */
-            continue;
+        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;
         }
-        OBJ_DROP_PROPERTY(cx, obj2, prop);
-#endif
-
-        if (!OBJ_SET_PROPERTY(cx, obj, id, &v2))
-            return JS_FALSE;
-        if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
-            return JS_FALSE;
     }
+    ok = JS_TRUE;
 
+  out:
+    if (len > JSVAL_INT_MAX + 1)
+        JS_UNKEEP_ATOMS(cx->runtime);
     *rval = OBJECT_TO_JSVAL(obj);
-    return JS_TRUE;
+    return ok;
+
+  bad:
+    ok = JS_FALSE;
+    goto out;
 }
 
 typedef struct HSortArgs {
@@ -666,7 +765,7 @@ HeapSortHelper(JSBool building, HSortArgs *hsa, size_t lo, size_t hi)
         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.
@@ -703,16 +802,13 @@ HeapSortHelper(JSBool building, HSortArgs *hsa, size_t lo, size_t hi)
 #undef MEMCPY
 }
 
-JSBool
-js_HeapSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, void *arg) 
+void
+js_HeapSort(void *vec, size_t nel, void *pivot, size_t elsize,
+            JSComparator cmp, void *arg)
 {
-    void *pivot;
     HSortArgs hsa;
     size_t i;
 
-    pivot = malloc(elsize);
-    if (!pivot)
-        return JS_FALSE;
     hsa.vec = vec;
     hsa.elsize = elsize;
     hsa.pivot = pivot;
@@ -724,15 +820,13 @@ js_HeapSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, void *arg)
         HeapSortHelper(JS_TRUE, &hsa, i, nel);
     while (nel > 2)
         HeapSortHelper(JS_FALSE, &hsa, 1, --nel);
-
-    free(pivot);
-    return JS_TRUE;
 }
 
 typedef struct CompareArgs {
-    JSContext  *context;
-    jsval      fval;
-    JSBool     status;
+    JSContext   *context;
+    jsval       fval;
+    jsval       *localroot;     /* need one local root, for sort_compare */
+    JSBool      status;
 } CompareArgs;
 
 static int
@@ -742,46 +836,75 @@ sort_compare(const void *a, const void *b, void *arg)
     CompareArgs *ca = (CompareArgs *) arg;
     JSContext *cx = ca->context;
     jsdouble cmp = -1;
-    jsval fval, argv[2], rval;
+    jsval fval, argv[2], special;
     JSBool ok;
 
     fval = ca->fval;
-    if (fval == JSVAL_NULL) {
+
+    /*
+     * 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 if (av == JSVAL_VOID || bv == JSVAL_VOID) {
-            /* Put undefined properties at the end. */
-            cmp = (av == JSVAL_VOID) ? 1 : -1;
-        } else if ((astr = js_ValueToString(cx, av)) != NULL &&
-                   (bstr = js_ValueToString(cx, bv)) != NULL) {
-            cmp = js_CompareStrings(astr, bstr);
         } else {
-            ca->status = JS_FALSE;
+            /*
+             * 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, &rval);
+                             fval, 2, argv, ca->localroot);
         if (ok) {
-            ok = js_ValueToNumber(cx, rval, &cmp);
+            ok = js_ValueToNumber(cx, *ca->localroot, &cmp);
+
             /* Clamp cmp to -1, 0, 1. */
-            if (JSDOUBLE_IS_NaN(cmp)) {
-                /* XXX report some kind of error here?  ECMA talks about
-                 * 'consistent compare functions' that don't return NaN, but is
-                 * silent about what the result should be.  So we currently
-                 * ignore it.
-                 */
-                cmp = 0;
-            } else if (cmp != 0) {
-                cmp = cmp > 0 ? 1 : -1;
+            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;
+                }
             }
-        } else {
-            ca->status = ok;
         }
+        if (!ok)
+            ca->status = ok;
     }
     return (int)cmp;
 }
@@ -794,17 +917,13 @@ sort_compare_strings(const void *a, const void *b, void *arg)
     return (int) js_CompareStrings(JSVAL_TO_STRING(av), JSVAL_TO_STRING(bv));
 }
 
-/* XXXmccabe do the sort helper functions need to take int?  (Or can we claim
- * that 2^32 * 32 is too large to worry about?)  Something dumps when I change
- * to unsigned int; is qsort using -1 as a fencepost?
- */
 static JSBool
 array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    jsval fval;
+    jsval fval, *vec, *pivotroot;
     CompareArgs ca;
     jsuint len, newlen, i;
-    jsval *vec;
+    JSStackFrame *fp;
     jsid id;
     size_t nbytes;
 
@@ -835,80 +954,70 @@ array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     }
 
     /*
-     * Test for size_t overflow, which could lead to indexing beyond the end
-     * of the malloc'd vector.
+     * 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.
      */
-    nbytes = len * sizeof(jsval);
-    if (nbytes != (double) len * sizeof(jsval)) {
+    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;
 
-#if JS_HAS_SPARSE_ARRAYS
-    newlen = 0;
-#else
-    newlen = len;
-#endif
+    /* 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 = IndexToId(cx, i, &id);
+        ca.status = IndexToExistingId(cx, obj, i, &id);
         if (!ca.status)
             goto out;
-#if JS_HAS_SPARSE_ARRAYS
-        {
-            JSObject *obj2;
-            JSProperty *prop;
-            ca.status = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
-            if (!ca.status)
-                goto out;
-            if (!prop) {
-                vec[i] = JSVAL_VOID;
-                continue;
-            }
-            OBJ_DROP_PROPERTY(cx, obj2, prop);
-            newlen++;
+
+        if (id == JSID_HOLE) {
+            vec[i] = JSVAL_HOLE;
+            all_strings = JS_FALSE;
+            continue;
         }
-#endif
+        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]); 
+        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;
-    if (!js_HeapSort(vec, (size_t) len, sizeof(jsval),
-                     all_strings ? sort_compare_strings : sort_compare,
-                     &ca)) {
-        JS_ReportOutOfMemory(cx);
-        ca.status = JS_FALSE;
-    }
+    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);
-#if JS_HAS_SPARSE_ARRAYS
-        /* set length of newly-created array object to old length. */
-        if (ca.status && newlen < len) {
-            ca.status = js_SetLengthProperty(cx, obj, len);
-
-            /* Delete any leftover properties greater than newlen. */
-            while (ca.status && newlen < len) {
-                jsval junk;
-
-                ca.status = !IndexToId(cx, newlen, &id) ||
-                    !OBJ_DELETE_PROPERTY(cx, obj, id, &junk);
-                newlen++;
-            }
+
+        /* 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;
         }
-#endif
     }
 
 out:
@@ -943,7 +1052,7 @@ array_push(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
      * return the new array length.
      */
     length += argc;
-    if (cx->version == JSVERSION_1_2) {
+    if (JS_VERSION_IS_1_2(cx)) {
         *rval = argc ? argv[argc-1] : JSVAL_VOID;
     } else {
         if (!IndexToValue(cx, length, rval))
@@ -957,20 +1066,26 @@ 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--;
-        if (!IndexToId(cx, index, &id))
-            return JS_FALSE;
 
         /* Get the to-be-deleted property's value into rval. */
-        if (!OBJ_GET_PROPERTY(cx, obj, id, rval))
+        if (!IndexToId(cx, index, &id))
             return JS_FALSE;
 
-        if (!OBJ_DELETE_PROPERTY(cx, obj, id, &junk))
+        /* 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);
@@ -981,7 +1096,7 @@ array_shift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     jsuint length, i;
     jsid id, id2;
-    jsval v, junk;
+    jsval junk;
 
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
@@ -1000,16 +1115,23 @@ array_shift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             for (i = 1; i <= length; i++) {
                 if (!IndexToId(cx, i, &id))
                     return JS_FALSE;
-                if (!IndexToId(cx, i - 1, &id2))
+                if (!OBJ_GET_PROPERTY(cx, obj, id, &argv[0]))
                     return JS_FALSE;
-                if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+
+                /* 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, &v))
+                if (!OBJ_SET_PROPERTY(cx, obj, id2, &argv[0]))
                     return JS_FALSE;
             }
         }
 
-        /* Delete the only or last element. */
+        /*
+         * 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;
     }
@@ -1023,11 +1145,7 @@ array_unshift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     jsuint length, last;
     uintN i;
     jsid id, id2;
-    jsval v;
-#if JS_HAS_SPARSE_ARRAYS
-    JSObject *obj2;
-    JSProperty *prop;
-#endif
+    jsval *vp, junk;
 
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
@@ -1035,24 +1153,25 @@ array_unshift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         /* Slide up the array to make room for argc at the bottom. */
         if (length > 0) {
             last = length;
+            vp = argv + argc;
             while (last--) {
-                if (!IndexToId(cx, last, &id))
+                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 JS_HAS_SPARSE_ARRAYS
-                if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
-                    return JS_FALSE;
-                if (!prop) {
-                    OBJ_DELETE_PROPERTY(cx, obj, id2, &v); /* v is junk. */
-                    continue;
+                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;
                 }
-                OBJ_DROP_PROPERTY(cx, obj2, prop);
-#endif
-                if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
-                    return JS_FALSE;
-                if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
-                    return JS_FALSE;
             }
         }
 
@@ -1075,16 +1194,20 @@ array_unshift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 static JSBool
 array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
+    jsval *vp, junk;
     jsuint length, begin, end, count, delta, last;
-    uintN i;
     jsdouble d;
     jsid id, id2;
-    jsval v;
     JSObject *obj2;
+    uintN i;
 
-    /* Nothing to do if no args.  Otherwise lock and load length. */
+    /*
+     * 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;
 
@@ -1122,7 +1245,7 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         argv++;
     }
 
-    if (count == 1 && cx->version == JSVERSION_1_2) {
+    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
@@ -1139,7 +1262,7 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         if (!OBJ_GET_PROPERTY(cx, obj, id, rval))
             return JS_FALSE;
     } else {
-        if (cx->version != JSVERSION_1_2 || count > 0) {
+        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
@@ -1154,15 +1277,22 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             /* If there are elements to remove, put them into the return value. */
             if (count > 0) {
                 for (last = begin; last < end; last++) {
-                    if (!IndexToId(cx, last, &id))
+                    if (!IndexToExistingId(cx, obj, last, &id))
                         return JS_FALSE;
-                    if (!IndexToId(cx, last - begin, &id2))
+                    if (id == JSID_HOLE)
+                        continue;       /* don't fill holes in the new array */
+                    if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
                         return JS_FALSE;
-                    if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+
+                    /* 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, &v))
+                    if (!OBJ_SET_PROPERTY(cx, obj2, id2, vp))
                         return JS_FALSE;
                 }
+
+                if (!js_SetLengthProperty(cx, obj2, end - begin))
+                    return JS_FALSE;
             }
         }
     }
@@ -1173,27 +1303,45 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         last = length;
         /* (uint) end could be 0, so can't use vanilla >= test */
         while (last-- > end) {
-            if (!IndexToId(cx, last, &id))
+            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 (!OBJ_GET_PROPERTY(cx, obj, id, &v))
-                return JS_FALSE;
-            if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
-                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 (!IndexToId(cx, last, &id))
+            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 (!OBJ_GET_PROPERTY(cx, obj, id, &v))
-                return JS_FALSE;
-            if (!OBJ_SET_PROPERTY(cx, obj, id2, &v))
-                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;
     }
@@ -1218,12 +1366,15 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 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;
-    jsval v;
     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]));
@@ -1242,20 +1393,30 @@ array_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             aobj = JSVAL_TO_OBJECT(v);
             if (aobj && OBJ_GET_CLASS(cx, aobj) == &js_ArrayClass) {
                 if (!OBJ_GET_PROPERTY(cx, aobj,
-                                      (jsid)cx->runtime->atomState.lengthAtom,
-                                      &v)) {
+                                      ATOM_TO_JSID(cx->runtime->atomState
+                                                   .lengthAtom),
+                                      vp)) {
                     return JS_FALSE;
                 }
-                if (!ValueIsLength(cx, v, &alength))
+                if (!ValueIsLength(cx, *vp, &alength))
                     return JS_FALSE;
                 for (slot = 0; slot < alength; slot++) {
-                    if (!IndexToId(cx, slot, &id))
+                    if (!IndexToExistingId(cx, aobj, slot, &id))
                         return JS_FALSE;
-                    if (!IndexToId(cx, length + slot, &id2))
+                    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;
-                    if (!OBJ_GET_PROPERTY(cx, aobj, id, &v))
+
+                    /* 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, &v))
+                    if (!OBJ_SET_PROPERTY(cx, nobj, id2, vp))
                         return JS_FALSE;
                 }
                 length += alength;
@@ -1263,28 +1424,34 @@ array_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             }
         }
 
+        *vp = v;
         if (!IndexToId(cx, length, &id))
             return JS_FALSE;
-        if (!OBJ_SET_PROPERTY(cx, nobj, id, &v))
+        if (!OBJ_SET_PROPERTY(cx, nobj, id, vp))
             return JS_FALSE;
         length++;
     }
 
-    return JS_TRUE;
+    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;
-    jsval v;
 
+    /* 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;
@@ -1319,20 +1486,316 @@ array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         }
     }
 
+    if (begin > end)
+        begin = end;
+
     for (slot = begin; slot < end; slot++) {
-        if (!IndexToId(cx, slot, &id))
+        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_GET_PROPERTY(cx, obj, id, &v))
+        if (!OBJ_SET_PROPERTY(cx, nobj, id2, vp))
             return JS_FALSE;
-        if (!OBJ_SET_PROPERTY(cx, nobj, id2, &v))
+    }
+    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;
+        }
     }
-    *rval = OBJECT_TO_JSVAL(nobj);
+
+    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;
 }
-#endif /* JS_HAS_SEQUENCE_OPS */
+
+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
@@ -1343,22 +1806,32 @@ static JSFunctionSpec array_methods[] = {
 
     /* Perl-ish methods. */
 #if JS_HAS_SOME_PERL_FUN
-    {"join",                array_join,             1,0,0},
-    {"reverse",             array_reverse,          0,0,0},
-    {"sort",                array_sort,             1,0,0},
+    {"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,0,0},
-    {"pop",                 array_pop,              0,0,0},
-    {"shift",               array_shift,            0,0,0},
-    {"unshift",             array_unshift,          1,0,0},
-    {"splice",              array_splice,           1,0,0},
+    {"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,           0,0,0},
-    {"slice",               array_slice,            0,0,0},
+    {"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}
@@ -1381,7 +1854,7 @@ Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     if (argc == 0) {
         length = 0;
         vector = NULL;
-    } else if (cx->version == JSVERSION_1_2) {
+    } else if (JS_VERSION_IS_1_2(cx)) {
         length = (jsuint) argc;
         vector = argv;
     } else if (argc > 1) {
index cbb2aedf1aa3ea591b09ec5e88f7c69a5a0e9a5a..0f43bee079a08d9bb4f098b8150dc669aaf1805a 100644 (file)
@@ -47,6 +47,9 @@
 
 JS_BEGIN_EXTERN_C
 
+extern JSBool
+js_IdIsIndex(jsval id, jsuint *indexp);
+
 extern JSClass js_ArrayClass;
 
 extern JSObject *
@@ -69,8 +72,9 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
  */
 typedef int (*JSComparator)(const void *a, const void *b, void *arg);
 
-extern JSBool
-js_HeapSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, void *arg);
+extern void
+js_HeapSort(void *vec, size_t nel, void *pivot, size_t elsize,
+            JSComparator cmp, void *arg);
 
 JS_END_EXTERN_C
 
index ede2350b6ec11e372bedfe2d54b6e54f46ca1487..6de628aefd54821ee3f8e537a1985af455caedae 100644 (file)
@@ -50,6 +50,7 @@
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
+#include "jsconfig.h"
 #include "jsgc.h"
 #include "jslock.h"
 #include "jsnum.h"
 JS_FRIEND_API(const char *)
 js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
 {
-    JSString *str;
-    const char *bytes;
-
-    str = js_QuoteString(cx, ATOM_TO_STRING(atom), 0);
-    if (!str)
-        return NULL;
-    bytes = js_GetStringBytes(str);
-    if (!bytes)
-        JS_ReportOutOfMemory(cx);
-    return bytes;
+    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
@@ -79,11 +73,13 @@ extern const char js_Error_str[];       /* trivial, from jsexn.h */
  */
 const char *js_type_str[] = {
     "undefined",
-    "object",
+    js_object_str,
     "function",
     "string",
     "number",
     "boolean",
+    "null",
+    "xml",
 };
 
 const char *js_boolean_str[] = {
@@ -98,11 +94,15 @@ 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";
@@ -111,6 +111,7 @@ 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";
@@ -119,7 +120,9 @@ 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";
@@ -128,6 +131,19 @@ 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_namespace_str[]       = "namespace";
+const char js_ptagc_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__";
@@ -136,9 +152,9 @@ const char js_ExecutionContext_str[] = "ExecutionContext";
 const char js_current_str[]          = "current";
 #endif
 
-#define HASH_OBJECT(o)  ((JSHashNumber)(o) >> JSVAL_TAGBITS)
+#define HASH_OBJECT(o)  (JS_PTR_TO_UINT32(o) >> JSVAL_TAGBITS)
 #define HASH_INT(i)     ((JSHashNumber)(i))
-#define HASH_DOUBLE(dp) ((JSHashNumber)(JSDOUBLE_HI32(*dp) ^ JSDOUBLE_LO32(*dp)))
+#define HASH_DOUBLE(dp) ((JSDOUBLE_HI32(*dp) ^ JSDOUBLE_LO32(*dp)))
 #define HASH_BOOLEAN(b) ((JSHashNumber)(b))
 
 JS_STATIC_DLL_CALLBACK(JSHashNumber)
@@ -291,14 +307,20 @@ js_InitPinnedAtoms(JSContext *cx, JSAtomState *state)
     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);
@@ -307,6 +329,7 @@ js_InitPinnedAtoms(JSContext *cx, JSAtomState *state)
     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);
@@ -324,6 +347,19 @@ js_InitPinnedAtoms(JSContext *cx, JSAtomState *state)
     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);
@@ -445,7 +481,7 @@ js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
         return HT_ENUMERATE_NEXT;
     }
     JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
-    atom->entry.key = NULL;
+    atom->entry.key = atom->entry.value = NULL;
     atom->flags = 0;
     return HT_ENUMERATE_REMOVE;
 }
@@ -595,6 +631,12 @@ out:
     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)
 {
@@ -606,6 +648,8 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
     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);
@@ -651,7 +695,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
     }
 
     atom = (JSAtom *)he;
-    atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED);
+    atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED | ATOM_HIDDEN);
     cx->lastAtom = atom;
 out:
     JS_UNLOCK(&state->lock,cx);
@@ -675,12 +719,15 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
      */
 #define ATOMIZE_BUF_MAX 32
     jschar inflated[ATOMIZE_BUF_MAX];
+    size_t inflatedLength = ATOMIZE_BUF_MAX - 1;
 
     if (length < ATOMIZE_BUF_MAX) {
-        js_InflateStringToBuffer(inflated, bytes, length);
+        js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength);
+        inflated[inflatedLength] = 0;
         chars = inflated;
     } else {
-        chars = js_InflateString(cx, bytes, length);
+        inflatedLength = length;
+        chars = js_InflateString(cx, bytes, &inflatedLength);
         if (!chars)
             return NULL;
         flags |= ATOM_NOCOPY;
@@ -689,7 +736,7 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
     str = ALIGN(buf, JSString);
 
     str->chars = chars;
-    str->length = length;
+    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);
@@ -805,12 +852,18 @@ js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al)
             if (!al->table) {
                 /* No hash table yet, so hep had better be null! */
                 JS_ASSERT(!hep);
-                al->table = JS_NewHashTable(8, js_hash_atom_ptr,
+                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);
index 6f486c3371f6e548185766d56b5e344f9cf713d8..f8ce3f90f7785b7ffc5b1000a9d138b32b56d140 100644 (file)
@@ -58,11 +58,13 @@ 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 */
+    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 */
 };
@@ -95,14 +97,14 @@ struct JSAtomListElement {
 };
 
 #define ALE_ATOM(ale)   ((JSAtom *) (ale)->entry.key)
-#define ALE_INDEX(ale)  ((jsatomid) (ale)->entry.value)
+#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 = (void *)(index))
-#define ALE_SET_JSOP(ale,op)    ((ale)->entry.value = (void *)(op))
+#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))
 
@@ -153,6 +155,9 @@ struct JSAtomState {
     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];
@@ -167,11 +172,15 @@ struct JSAtomState {
     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;
@@ -180,6 +189,8 @@ struct JSAtomState {
     JSAtom              *classPrototypeAtom;
     JSAtom              *constructorAtom;
     JSAtom              *countAtom;
+    JSAtom              *eachAtom;
+    JSAtom              *etagoAtom;
     JSAtom              *evalAtom;
     JSAtom              *getAtom;
     JSAtom              *getterAtom;
@@ -187,18 +198,29 @@ struct JSAtomState {
     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;
@@ -208,6 +230,7 @@ struct JSAtomState {
         JSAtom          *SyntaxErrorAtom;
         JSAtom          *TypeErrorAtom;
         JSAtom          *URIErrorAtom;
+        JSAtom          *XMLListAtom;
         JSAtom          *decodeURIAtom;
         JSAtom          *decodeURIComponentAtom;
         JSAtom          *defineGetterAtom;
@@ -215,10 +238,12 @@ struct JSAtomState {
         JSAtom          *encodeURIAtom;
         JSAtom          *encodeURIComponentAtom;
         JSAtom          *escapeAtom;
+        JSAtom          *functionNamespaceURIAtom;
         JSAtom          *hasOwnPropertyAtom;
         JSAtom          *isFiniteAtom;
         JSAtom          *isNaNAtom;
         JSAtom          *isPrototypeOfAtom;
+        JSAtom          *isXMLNameAtom;
         JSAtom          *lookupGetterAtom;
         JSAtom          *lookupSetterAtom;
         JSAtom          *parseFloatAtom;
@@ -254,11 +279,15 @@ 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[];
@@ -267,6 +296,8 @@ 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[];
@@ -274,15 +305,26 @@ 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[];
index 75d4ee05af0185cb18e368d1edd001a2c710b14e..33d5c507eed1eb4f1cbec3ebc5fe72cbe59d1b27 100644 (file)
@@ -54,7 +54,7 @@
 #include "jsobj.h"
 #include "jsstr.h"
 
-static JSClass boolean_class = {
+JSClass js_BooleanClass = {
     "Boolean",
     JSCLASS_HAS_PRIVATE,
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
@@ -67,23 +67,23 @@ static JSClass boolean_class = {
 
 static JSBool
 bool_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+              jsval *rval)
 {
     jsval v;
     char buf[32];
     JSString *str;
 
-    if (!JS_InstanceOf(cx, obj, &boolean_class, argv))
-       return JS_FALSE;
+    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);
+        return js_obj_toSource(cx, obj, argc, argv, rval);
     JS_snprintf(buf, sizeof buf, "(new %s(%s))",
-               boolean_class.name,
-               js_boolean_str[JSVAL_TO_BOOLEAN(v) ? 1 : 0]);
+                js_BooleanClass.name,
+                js_boolean_str[JSVAL_TO_BOOLEAN(v) ? 1 : 0]);
     str = JS_NewStringCopyZ(cx, buf);
     if (!str)
-       return JS_FALSE;
+        return JS_FALSE;
     *rval = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
@@ -91,21 +91,21 @@ bool_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 bool_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+              jsval *rval)
 {
     jsval v;
     JSAtom *atom;
     JSString *str;
 
-    if (!JS_InstanceOf(cx, obj, &boolean_class, argv))
-       return JS_FALSE;
+    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);
+        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;
+        return JS_FALSE;
     *rval = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
@@ -113,8 +113,8 @@ bool_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 static JSBool
 bool_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    if (!JS_InstanceOf(cx, obj, &boolean_class, argv))
-       return JS_FALSE;
+    if (!JS_InstanceOf(cx, obj, &js_BooleanClass, argv))
+        return JS_FALSE;
     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
     return JS_TRUE;
 }
@@ -123,16 +123,11 @@ 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},
+    {js_toString_str,   bool_toString,          0,0,0},
+    {js_valueOf_str,    bool_valueOf,           0,0,0},
     {0,0,0,0,0}
 };
 
-#ifdef XP_MAC
-#undef Boolean
-#define Boolean js_Boolean
-#endif
-
 static JSBool
 Boolean(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
@@ -140,15 +135,15 @@ Boolean(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     jsval bval;
 
     if (argc != 0) {
-       if (!js_ValueToBoolean(cx, argv[0], &b))
-           return JS_FALSE;
-       bval = BOOLEAN_TO_JSVAL(b);
+        if (!js_ValueToBoolean(cx, argv[0], &b))
+            return JS_FALSE;
+        bval = BOOLEAN_TO_JSVAL(b);
     } else {
-       bval = JSVAL_FALSE;
+        bval = JSVAL_FALSE;
     }
     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
-       *rval = bval;
-       return JS_TRUE;
+        *rval = bval;
+        return JS_TRUE;
     }
     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, bval);
     return JS_TRUE;
@@ -159,10 +154,10 @@ js_InitBooleanClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto;
 
-    proto = JS_InitClass(cx, obj, NULL, &boolean_class, Boolean, 1,
-                       NULL, boolean_methods, NULL, NULL);
+    proto = JS_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1,
+                        NULL, boolean_methods, NULL, NULL);
     if (!proto)
-       return NULL;
+        return NULL;
     OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE, JSVAL_FALSE);
     return proto;
 }
@@ -172,9 +167,9 @@ js_BooleanToObject(JSContext *cx, JSBool b)
 {
     JSObject *obj;
 
-    obj = js_NewObject(cx, &boolean_class, NULL, NULL);
+    obj = js_NewObject(cx, &js_BooleanClass, NULL, NULL);
     if (!obj)
-       return NULL;
+        return NULL;
     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, BOOLEAN_TO_JSVAL(b));
     return obj;
 }
@@ -192,27 +187,27 @@ js_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
     jsdouble d;
 
     if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) {
-       b = JS_FALSE;
+        b = JS_FALSE;
     } else if (JSVAL_IS_OBJECT(v)) {
-       if (!JSVERSION_IS_ECMA(cx->version)) {
-           if (!OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), JSTYPE_BOOLEAN, &v))
-               return JS_FALSE;
-           if (!JSVAL_IS_BOOLEAN(v))
-               v = JSVAL_TRUE;         /* non-null object is true */
-           b = JSVAL_TO_BOOLEAN(v);
-       } else {
-           b = JS_TRUE;
-       }
+        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;
+        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;
+        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;
+        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);
+        b = JSVAL_TO_BOOLEAN(v);
     }
 
     *bp = b;
index c07910f59c04a63607af0253cd61f204a432b4c3..770b94c6ded71ab66442bdb44cbfb0870392ab5a 100644 (file)
 
 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);
 
index 2eafe8e403b0765e21e514233d4265af0830f81a..604ec0ec95637af2ead25d1124ced0c62d3d934f 100644 (file)
@@ -52,35 +52,35 @@ typedef struct JSCListStr {
 /*
 ** 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);       \
+#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);       \
+#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)
+#define JS_NEXT_LINK(_e)         \
+        ((_e)->next)
 /*
 ** Return the element preceding element "_e"
 */
-#define JS_PREV_LINK(_e)        \
-       ((_e)->prev)
+#define JS_PREV_LINK(_e)         \
+        ((_e)->prev)
 
 /*
 ** Append an element "_e" to the end of the list "_l"
@@ -99,10 +99,10 @@ typedef struct JSCListStr {
 /*
 ** 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; \
+#define JS_REMOVE_LINK(_e)             \
+    JS_BEGIN_MACRO                     \
+        (_e)->prev->next = (_e)->next; \
+        (_e)->next->prev = (_e)->prev; \
     JS_END_MACRO
 
 /*
@@ -110,11 +110,11 @@ typedef struct JSCListStr {
 ** 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_BEGIN_MACRO                     \
+        (_e)->prev->next = (_e)->next; \
+        (_e)->next->prev = (_e)->prev; \
+        (_e)->next = (_e);             \
+        (_e)->prev = (_e);             \
     JS_END_MACRO
 
 /*
@@ -128,9 +128,9 @@ typedef struct JSCListStr {
 ** Initialize a circular list
 */
 #define JS_INIT_CLIST(_l)  \
-    JS_BEGIN_MACRO        \
-       (_l)->next = (_l); \
-       (_l)->prev = (_l); \
+    JS_BEGIN_MACRO         \
+        (_l)->next = (_l); \
+        (_l)->prev = (_l); \
     JS_END_MACRO
 
 #define JS_INIT_STATIC_CLIST(_l) \
index de254ca9cfca5ab91e70e7e3700cf9871e4b9047..43041f97b3ab5fa4a94f37c7435e1f75fe430608 100644 (file)
 #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)
 {
@@ -131,15 +152,22 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
      * 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_InitRuntimeScriptState(cx);
         if (ok)
             ok = js_InitRuntimeStringState(cx);
         if (!ok) {
@@ -242,8 +270,9 @@ js_DestroyContext(JSContext *cx, JSGCMode gcmode)
         if (rt->atomState.liveAtoms == 0)
             js_FreeAtomState(cx, &rt->atomState);
 
-        /* Now after the last GC can we free the script filename table. */
-        js_FinishRuntimeScriptState(cx);
+        /* 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);
@@ -334,7 +363,7 @@ resolving_HashKey(JSDHashTable *table, const void *ptr)
 {
     const JSResolvingKey *key = (const JSResolvingKey *)ptr;
 
-    return ((JSDHashNumber)key->obj >> JSVAL_TAGBITS) ^ key->id;
+    return ((JSDHashNumber)JS_PTR_TO_UINT32(key->obj) >> JSVAL_TAGBITS) ^ key->id;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -454,7 +483,7 @@ js_EnterLocalRootScope(JSContext *cx)
     mark = js_PushLocalRoot(cx, lrs, INT_TO_JSVAL(lrs->scopeMark));
     if (mark < 0)
         return JS_FALSE;
-    lrs->scopeMark = (uint16) mark;
+    lrs->scopeMark = (uint32) mark;
     return JS_TRUE;
 }
 
@@ -490,9 +519,9 @@ js_LeaveLocalRootScope(JSContext *cx)
     /* Pop the scope, restoring lrs->scopeMark. */
     lrc = lrs->topChunk;
     m = mark & JSLRS_CHUNK_MASK;
-    lrs->scopeMark = JSVAL_TO_INT(lrc->roots[m]);
+    lrs->scopeMark = (uint32) JSVAL_TO_INT(lrc->roots[m]);
     lrc->roots[m] = JSVAL_NULL;
-    lrs->rootCount = (uint16) mark;
+    lrs->rootCount = (uint32) mark;
 
     /*
      * Free the stack eagerly, risking malloc churn.  The alternative would
@@ -584,7 +613,7 @@ js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v)
          * At start of first chunk, or not at start of a non-first top chunk.
          * Check for lrs->rootCount overflow.
          */
-        if ((uint16)(n + 1) == 0) {
+        if ((uint32)(n + 1) == 0) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TOO_MANY_LOCAL_ROOTS);
             return -1;
@@ -604,7 +633,7 @@ js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v)
     }
     lrs->rootCount = n + 1;
     lrc->roots[m] = v;
-    return (int) m;
+    return (int) n;
 }
 
 void
@@ -619,19 +648,26 @@ js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs)
 
     mark = lrs->scopeMark;
     lrc = lrs->topChunk;
-    while (--n > mark) {
+    do {
+        while (--n > mark) {
 #ifdef GC_MARK_DEBUG
-        char name[22];
-        JS_snprintf(name, sizeof name, "<local root %u>", n);
+            char name[22];
+            JS_snprintf(name, sizeof name, "<local root %u>", n);
 #else
-        const char *name = NULL;
+            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;
-        JS_ASSERT(JSVAL_IS_GCTHING(lrc->roots[m]));
-        JS_MarkGCThing(cx, JSVAL_TO_GCTHING(lrc->roots[m]), name, NULL);
+        mark = JSVAL_TO_INT(lrc->roots[m]);
         if (m == 0)
             lrc = lrc->down;
-    }
+    } while (n != 0);
+    JS_ASSERT(!lrc);
 }
 
 static void
@@ -807,8 +843,9 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
                 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, strlen(charArg));
+                            = js_InflateString(cx, charArg, &charArgLength);
                         if (!reportp->messageArgs[i])
                             goto error;
                     }
@@ -826,12 +863,16 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
              */
             if (argCount > 0) {
                 if (efs->format) {
-                    const char *fmt;
+                    jschar *buffer, *fmt, *out;
                     const jschar *arg;
-                    jschar *out;
                     int expandedArgs = 0;
-                    size_t expandedLength
-                        = strlen(efs->format)
+                    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;
                     /*
@@ -840,14 +881,15 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
                      */
                     reportp->ucmessage = out = (jschar *)
                         JS_malloc(cx, (expandedLength + 1) * sizeof(jschar));
-                    if (!out)
+                    if (!out) {
+                        JS_free (cx, buffer);
                         goto error;
-                    fmt = efs->format;
+                    }
                     while (*fmt) {
                         if (*fmt == '{') {
                             if (isdigit(fmt[1])) {
                                 int d = JS7_UNDEC(fmt[1]);
-                                JS_ASSERT(expandedArgs < argCount);
+                                JS_ASSERT(d < argCount);
                                 arg = reportp->messageArgs[d];
                                 js_strncpy(out, arg, argLengths[d]);
                                 out += argLengths[d];
@@ -856,13 +898,11 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
                                 continue;
                             }
                         }
-                        /*
-                         * is this kosher?
-                         */
-                        *out++ = (unsigned char)(*fmt++);
+                         *out++ = *fmt++;
                     }
                     JS_ASSERT(expandedArgs == argCount);
                     *out = 0;
+                    JS_free (cx, buffer);
                     *messagep =
                         js_DeflateString(cx, reportp->ucmessage,
                                          (size_t)(out - reportp->ucmessage));
@@ -875,11 +915,13 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
                  * 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, strlen(*messagep));
+                        = js_InflateString(cx, *messagep, &len);
                     if (!reportp->ucmessage)
                         goto error;
                 }
index 630d6a63f1e39b4fbb13c0495cdac0534a7bd322..bf49c8b8e720c924dd58913576c5b531a63b7c78 100644 (file)
@@ -54,6 +54,7 @@
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsregexp.h"
+#include "jsutil.h"
 
 JS_BEGIN_EXTERN_C
 
@@ -71,25 +72,51 @@ typedef struct JSPropertyTreeEntry {
     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;
+    JSArenaPool         gcArenaPool[GC_NUM_FREELISTS];
+    JSGCThing           *gcFreeList[GC_NUM_FREELISTS];
     JSDHashTable        gcRootsHash;
     JSDHashTable        *gcLocksHash;
-    JSGCThing           *gcFreeList;
     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
@@ -204,6 +231,9 @@ struct JSRuntime {
     /* 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;
@@ -211,6 +241,7 @@ struct JSRuntime {
 
     /* Script filename table. */
     struct JSHashTable  *scriptFilenameTable;
+    JSCList             scriptFilenamePrefixes;
 #ifdef JS_THREADSAFE
     PRLock              *scriptFilenameTableLock;
 #endif
@@ -220,6 +251,22 @@ struct JSRuntime {
     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;
@@ -310,7 +357,7 @@ typedef struct JSResolvingEntry {
 
 typedef struct JSLocalRootChunk JSLocalRootChunk;
 
-#define JSLRS_CHUNK_SHIFT       6
+#define JSLRS_CHUNK_SHIFT       8
 #define JSLRS_CHUNK_SIZE        JS_BIT(JSLRS_CHUNK_SHIFT)
 #define JSLRS_CHUNK_MASK        JS_BITMASK(JSLRS_CHUNK_SHIFT)
 
@@ -320,13 +367,106 @@ struct JSLocalRootChunk {
 };
 
 typedef struct JSLocalRootStack {
-    uint16              scopeMark;
-    uint16              rootCount;
+    uint32              scopeMark;
+    uint32              rootCount;
     JSLocalRootChunk    *topChunk;
     JSLocalRootChunk    firstChunk;
 } JSLocalRootStack;
 
-#define JSLRS_NULL_MARK ((uint16) -1)
+#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;
@@ -338,7 +478,7 @@ struct JSContext {
     jsuword             stackLimit;
 
     /* Runtime version control identifier and equality operators. */
-    JSVersion           version;
+    uint16              version;
     jsbytecode          jsop_eq;
     jsbytecode          jsop_ne;
 
@@ -361,6 +501,9 @@ struct JSContext {
     /* 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;
 
@@ -404,10 +547,20 @@ struct JSContext {
     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,
-     * and with throwing, below.
+     * NB: creatingException packs with rval2set, #if JS_HAS_LVALUE_RETURN;
+     * with xmlSettingFlags, #if JS_HAS_XML_SUPPORT; and with throwing below.
      */
     JSPackedBool        creatingException;
 
@@ -435,22 +588,108 @@ struct JSContext {
     /* PDL of stack headers describing stack slots not rooted by argv, etc. */
     JSStackHeader       *stackHeaders;
 
-    /* Optional hook to find principals for an object being accessed on cx. */
-    JSObjectPrincipalsFinder findObjectPrincipals;
-
-    /* Optional stack of scoped local GC roots. */
+    /* 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);
+    }
+
+    ~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)
+
 /*
- * Slightly more readable macros, also to hide bitset implementation detail.
- * XXX beware non-boolean truth values, which belie the bitset hiding claim!
+ * 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_HAS_STRICT_OPTION(cx)        ((cx)->options & JSOPTION_STRICT)
-#define JS_HAS_WERROR_OPTION(cx)        ((cx)->options & JSOPTION_WERROR)
-#define JS_HAS_COMPILE_N_GO_OPTION(cx)  ((cx)->options & JSOPTION_COMPILE_N_GO)
-#define JS_HAS_ATLINE_OPTION(cx)        ((cx)->options & JSOPTION_ATLINE)
+#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);
 
index 44a64d87027e7c98585f70bb3ac095a97053c3a8..5902499f90e85182cc55b96a6bbc41644ebe38e7 100644 (file)
  * JS configuration macros.
  */
 #ifndef JS_VERSION
-#define JS_VERSION 150
+#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.0     1.1     1.2     1.3     1.4     ECMAv3  1.5     1.6
  *              ^                       ^
  *              |                       |
  *              basis for ECMAv1        close to ECMAv2
 #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_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_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_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_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_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_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
 
diff --git a/src/dom/js/jsconfig.mk b/src/dom/js/jsconfig.mk
deleted file mode 100644 (file)
index a3b8867..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-# -*- Mode: makefile -*-
-# 
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and 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 *****
-
-ifndef OBJDIR
-  ifdef OBJDIR_NAME
-    OBJDIR = $(OBJDIR_NAME)
-  endif
-endif
-
-NSPR_VERSION = v4.0
-NSPR_LIBSUFFIX = 4
-
-NSPR_LOCAL       = $(MOZ_DEPTH)/dist/$(OBJDIR)/nspr
-NSPR_DIST        = $(MOZ_DEPTH)/dist/$(OBJDIR)
-NSPR_OBJDIR      = $(OBJDIR)
-ifeq ($(OS_ARCH), SunOS)
-  NSPR_OBJDIR   := $(subst _sparc,,$(NSPR_OBJDIR))
-endif
-ifeq ($(OS_ARCH), Linux)
-  LINUX_REL     := $(shell uname -r)
-  ifneq (,$(findstring 2.0,$(LINUX_REL)))
-    NSPR_OBJDIR := $(subst _All,2.0_x86_glibc_PTH,$(NSPR_OBJDIR))
-  else
-    NSPR_OBJDIR := $(subst _All,2.2_x86_glibc_PTH,$(NSPR_OBJDIR))
-  endif
-endif
-ifeq ($(OS_ARCH), AIX)
-  NSPR_OBJDIR   := $(subst 4.1,4.2,$(NSPR_OBJDIR))
-endif
-ifeq ($(OS_CONFIG), IRIX6.2)
-  NSPR_OBJDIR   := $(subst 6.2,6.2_n32_PTH,$(NSPR_OBJDIR))
-endif
-ifeq ($(OS_CONFIG), IRIX6.5)
-  NSPR_OBJDIR   := $(subst 6.5,6.5_n32_PTH,$(NSPR_OBJDIR))
-endif
-ifeq ($(OS_ARCH), WINNT)
-  ifeq ($(OBJDIR), WIN32_D.OBJ)
-    NSPR_OBJDIR  = WINNT4.0_DBG.OBJ
-  endif
-  ifeq ($(OBJDIR), WIN32_O.OBJ)
-    NSPR_OBJDIR  = WINNT4.0_OPT.OBJ
-  endif
-endif
-NSPR_SHARED      = /share/builds/components/nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR)
-ifeq ($(OS_ARCH), WINNT)
-  NSPR_SHARED    = nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR)
-endif
-NSPR_VERSIONFILE = $(NSPR_LOCAL)/Version
-NSPR_CURVERSION := $(shell cat $(NSPR_VERSIONFILE))
-
-get_nspr:
-       @echo "Grabbing NSPR component..."
-ifeq ($(NSPR_VERSION), $(NSPR_CURVERSION))
-       @echo "No need, NSPR is up to date in this tree (ver=$(NSPR_VERSION))."
-else
-       mkdir -p $(NSPR_LOCAL)
-       mkdir -p $(NSPR_DIST)
-  ifneq ($(OS_ARCH), WINNT)
-       cp       $(NSPR_SHARED)/*.jar $(NSPR_LOCAL)
-  else
-       sh       $(MOZ_DEPTH)/../reltools/compftp.sh $(NSPR_SHARED) $(NSPR_LOCAL) *.jar
-  endif
-       unzip -o $(NSPR_LOCAL)/mdbinary.jar -d $(NSPR_DIST)
-       mkdir -p $(NSPR_DIST)/include
-       unzip -o $(NSPR_LOCAL)/mdheader.jar -d $(NSPR_DIST)/include
-       rm -rf   $(NSPR_DIST)/META-INF
-       rm -rf   $(NSPR_DIST)/include/META-INF
-       echo $(NSPR_VERSION) > $(NSPR_VERSIONFILE)
-endif
-
-SHIP_DIST  = $(MOZ_DEPTH)/dist/$(OBJDIR)
-SHIP_DIR   = $(SHIP_DIST)/SHIP
-
-SHIP_LIBS      = libjs.$(SO_SUFFIX) libjs.a
-ifdef JS_LIVECONNECT
-  SHIP_LIBS   += libjsj.$(SO_SUFFIX) libjsj.a
-endif
-ifeq ($(OS_ARCH), WINNT)
-  SHIP_LIBS    = js32.dll js32.lib
-  ifdef JS_LIVECONNECT
-    SHIP_LIBS += jsj.dll jsj.lib
-  endif
-endif
-SHIP_LIBS     += $(LCJAR)
-SHIP_LIBS     := $(addprefix $(SHIP_DIST)/lib/, $(SHIP_LIBS))
-
-SHIP_INCS      = js*.h prmjtime.h resource.h *.msg *.tbl
-ifdef JS_LIVECONNECT
-  SHIP_INCS   += netscape*.h nsC*.h nsI*.h
-endif
-SHIP_INCS     := $(addprefix $(SHIP_DIST)/include/, $(SHIP_INCS))
-
-SHIP_BINS      = js
-ifdef JS_LIVECONNECT
-  SHIP_BINS   += lcshell
-endif
-ifeq ($(OS_ARCH), WINNT)
-  SHIP_BINS   := $(addsuffix .exe, $(SHIP_BINS))
-endif
-SHIP_BINS     := $(addprefix $(SHIP_DIST)/bin/, $(SHIP_BINS))
-
-ifdef BUILD_OPT
-  JSREFJAR = jsref_opt.jar
-else
-ifdef BUILD_IDG
-  JSREFJAR = jsref_idg.jar
-else
-  JSREFJAR = jsref_dbg.jar
-endif
-endif
-
-ship:
-       mkdir -p $(SHIP_DIR)/$(LIBDIR)
-       mkdir -p $(SHIP_DIR)/include
-       mkdir -p $(SHIP_DIR)/bin
-       cp $(SHIP_LIBS) $(SHIP_DIR)/$(LIBDIR)
-       cp $(SHIP_INCS) $(SHIP_DIR)/include
-       cp $(SHIP_BINS) $(SHIP_DIR)/bin
-       cd $(SHIP_DIR); \
-         zip -r $(JSREFJAR) bin lib include
-ifdef BUILD_SHIP
-       cp $(SHIP_DIR)/$(JSREFJAR) $(BUILD_SHIP)
-endif
-
-CWD = $(shell pwd)
-shipSource: $(SHIP_DIR)/jsref_src.lst .FORCE
-       mkdir -p $(SHIP_DIR)
-       cd $(MOZ_DEPTH)/.. ; \
-         zip $(CWD)/$(SHIP_DIR)/jsref_src.jar -@ < $(CWD)/$(SHIP_DIR)/jsref_src.lst
-ifdef BUILD_SHIP
-       cp $(SHIP_DIR)/jsref_src.jar $(BUILD_SHIP)
-endif
-
-JSREFSRCDIRS := $(shell cat $(DEPTH)/SpiderMonkey.rsp)
-$(SHIP_DIR)/jsref_src.lst: .FORCE
-       mkdir -p $(SHIP_DIR)
-       rm -f $@
-       touch $@
-       for d in $(JSREFSRCDIRS); do                                \
-         cd $(MOZ_DEPTH)/..;                                       \
-         ls -1 -d $$d | grep -v CVS | grep -v \.OBJ >> $(CWD)/$@;  \
-         cd $(CWD);                                                \
-       done
-
-.FORCE:
index aa6c04c4d5548c94cdbd9c2c3829a33409f2d4bb..e02f33615d51464c4e773cd056f259246fb02703 100644 (file)
 #define INT64 PRInt64
 #else
 
-#ifdef __MWERKS__
-#define XP_MAC 1
-#endif
-
 /************************************************************************/
 
 /* Generate cpucfg.h */
-#ifdef XP_MAC
-#include <Types.h>
-#define INT64  UnsignedWide
-#else
+
 #if defined(XP_WIN) || defined(XP_OS2)
 #ifdef WIN32
 #if defined(__GNUC__)
 #define INT64   long long
 #else
-#define INT64  _int64
+#define INT64   _int64
 #endif /* __GNUC__ */
 #else
-#define INT64  long
+#define INT64   long
 #endif
 #else
 #if defined(HPUX) || defined(__QNX__) || defined(_SCO_DS) || defined(UNIXWARE)
-#define INT64  long
+#define INT64   long
 #else
-#define INT64  long long
-#endif
+#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 {
@@ -102,7 +100,7 @@ struct align_int64 {
 struct align_fakelonglong {
     char c;
     struct {
-       long hi, lo;
+        long hi, lo;
     } a;
 };
 struct align_float {
@@ -132,17 +130,17 @@ static int Log2(unsigned int n)
     int log2 = 0;
 
     if (n & (n-1))
-       log2++;
+        log2++;
     if (n >> 16)
-       log2 += 16, n >>= 16;
+        log2 += 16, n >>= 16;
     if (n >> 8)
-       log2 += 8, n >>= 8;
+        log2 += 8, n >>= 8;
     if (n >> 4)
-       log2 += 4, n >>= 4;
+        log2 += 4, n >>= 4;
     if (n >> 2)
-       log2 += 2, n >>= 2;
+        log2 += 2, n >>= 2;
     if (n >> 1)
-       log2++;
+        log2++;
     return log2;
 }
 
@@ -156,7 +154,7 @@ static void BitsPerByte(void)
     bpb = 8;
 }
 
-static int StackGrowthDirection(int *dummy1addr)
+static int NS_NEVER_INLINE StackGrowthDirection(int *dummy1addr)
 {
     int dummy2;
 
@@ -190,26 +188,26 @@ int main(int argc, char **argv)
 #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;
+    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;
+    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 */
 
@@ -222,10 +220,10 @@ int main(int argc, char **argv)
         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 - 
+            /* 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 
+             * (|static| is used to get the same functionality for compilers
              * which do not honor |volatile|...).
              */
             volatile static union {
@@ -287,37 +285,37 @@ int main(int argc, char **argv)
             printf("#undef  IS_BIG_ENDIAN\n\n");
         } else {
             fprintf(stderr, "%s: unknown byte order"
-                    "(big_endian=%d, little_endian=%d, ntests=%d)!\n", 
+                    "(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;
+    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);
+    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);
+        /* this machine doesn't actually support int64's */
+        align_of_int64  = ALIGN_OF(fakelonglong);
     } else {
-        align_of_int64 = ALIGN_OF(int64);
+        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);
+    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 */
 
index 897ee577cfe9b0f2ec454b8db4b9b892c6e31903..7b8b2add45b4aa9ed72feea926a3c72bae09dc8d 100644 (file)
 
 #include "jsosdep.h"
 
-#ifdef XP_MAC
-#undef  IS_LITTLE_ENDIAN
-#define IS_BIG_ENDIAN 1
-
-#define JS_BYTES_PER_BYTE   1L
-#define JS_BYTES_PER_SHORT  2L
-#define JS_BYTES_PER_INT    4L
-#define JS_BYTES_PER_INT64  8L
-#define JS_BYTES_PER_LONG   4L
-#define JS_BYTES_PER_FLOAT  4L
-#define JS_BYTES_PER_DOUBLE 8L
-#define JS_BYTES_PER_WORD   4L
-#define JS_BYTES_PER_DWORD  8L
-
-#define JS_BITS_PER_BYTE    8L
-#define JS_BITS_PER_SHORT   16L
-#define JS_BITS_PER_INT     32L
-#define JS_BITS_PER_INT64   64L
-#define JS_BITS_PER_LONG    32L
-#define JS_BITS_PER_FLOAT   32L
-#define JS_BITS_PER_DOUBLE  64L
-#define JS_BITS_PER_WORD    32L
-
-#define JS_BITS_PER_BYTE_LOG2   3L
-#define JS_BITS_PER_SHORT_LOG2  4L
-#define JS_BITS_PER_INT_LOG2    5L
-#define JS_BITS_PER_INT64_LOG2  6L
-#define JS_BITS_PER_LONG_LOG2   5L
-#define JS_BITS_PER_FLOAT_LOG2  5L
-#define JS_BITS_PER_DOUBLE_LOG2 6L
-#define JS_BITS_PER_WORD_LOG2   5L
-
-#define JS_ALIGN_OF_SHORT   2L
-#define JS_ALIGN_OF_INT     4L
-#define JS_ALIGN_OF_LONG    4L
-#define JS_ALIGN_OF_INT64   2L
-#define JS_ALIGN_OF_FLOAT   4L
-#define JS_ALIGN_OF_DOUBLE  4L
-#define JS_ALIGN_OF_POINTER 4L
-#define JS_ALIGN_OF_WORD    4L
-
-#define JS_BYTES_PER_WORD_LOG2   2L
-#define JS_BYTES_PER_DWORD_LOG2  3L
-#define PR_WORDS_PER_DWORD_LOG2  1L
-
-#elif defined(XP_WIN) || defined(XP_OS2)
+#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE)
 
 #ifdef __WATCOMC__
 #define HAVE_VA_LIST_AS_ARRAY
 #endif
 
-#if defined( _WIN32) || defined(XP_OS2)
+#if defined(_WIN32) || defined(XP_OS2) || defined(WINCE)
 #define IS_LITTLE_ENDIAN 1
 #undef  IS_BIG_ENDIAN
 
 #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 */
+#endif /* _WIN32 || XP_OS2 || WINCE*/
 
 #if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */
 #define IS_LITTLE_ENDIAN 1
 
 #else
 
-#error "Must define one of XP_BEOS, XP_MAC, XP_OS2, XP_WIN, or XP_UNIX"
+#error "Must define one of XP_BEOS, XP_OS2, XP_WIN, or XP_UNIX"
 
 #endif
 
index 4d85b1ef73f16d0c5e3acd718be020e602a080a8..a76502c38e0797c08ad4c1f4a21221bcd5b722ac 100644 (file)
@@ -179,18 +179,18 @@ TimeWithinDay(jsdouble t)
     jsdouble result;
     result = fmod(t, msPerDay);
     if (result < 0)
-       result += msPerDay;
+        result += msPerDay;
     return result;
 }
 
 #define DaysInYear(y)   ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0))  \
-                        ? 366 : 365)
+                         ? 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))
+                         - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
 #define TimeFromYear(y) (DayFromYear(y) * msPerDay)
 
 static jsint
@@ -231,28 +231,28 @@ MonthFromTime(jsdouble t)
     d = DayWithinYear(t, year);
 
     if (d < (step = 31))
-       return 0;
+        return 0;
     step += (InLeapYear(t) ? 29 : 28);
     if (d < step)
-       return 1;
+        return 1;
     if (d < (step += 31))
-       return 2;
+        return 2;
     if (d < (step += 30))
-       return 3;
+        return 3;
     if (d < (step += 31))
-       return 4;
+        return 4;
     if (d < (step += 30))
-       return 5;
+        return 5;
     if (d < (step += 31))
-       return 6;
+        return 6;
     if (d < (step += 31))
-       return 7;
+        return 7;
     if (d < (step += 30))
-       return 8;
+        return 8;
     if (d < (step += 31))
-       return 9;
+        return 9;
     if (d < (step += 30))
-       return 10;
+        return 10;
     return 11;
 }
 
@@ -264,38 +264,38 @@ DateFromTime(jsdouble t)
     d = DayWithinYear(t, year);
 
     if (d <= (next = 30))
-       return d + 1;
+        return d + 1;
     step = next;
     next += (InLeapYear(t) ? 29 : 28);
     if (d <= next)
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 31))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 30))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 31))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 30))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 31))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 31))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 30))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 31))
-       return d - step;
+        return d - step;
     step = next;
     if (d <= (next += 30))
-       return d - step;
+        return d - step;
     step = next;
     return d - step;
 }
@@ -307,10 +307,72 @@ WeekDay(jsdouble t)
     result = (jsint) Day(t) + 4;
     result = result % 7;
     if (result < 0)
-       result += 7;
+        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;
 
@@ -324,7 +386,20 @@ DaylightSavingTA(jsdouble t)
 
     /* abort if NaN */
     if (JSDOUBLE_IS_NaN(t))
-       return 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);
@@ -354,7 +429,7 @@ HourFromTime(jsdouble t)
 {
     intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
     if (result < 0)
-       result += (intN)HoursPerDay;
+        result += (intN)HoursPerDay;
     return result;
 }
 
@@ -363,7 +438,7 @@ MinFromTime(jsdouble t)
 {
     intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
     if (result < 0)
-       result += (intN)MinutesPerHour;
+        result += (intN)MinutesPerHour;
     return result;
 }
 
@@ -372,7 +447,7 @@ SecFromTime(jsdouble t)
 {
     intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
     if (result < 0)
-       result += (intN)SecondsPerMinute;
+        result += (intN)SecondsPerMinute;
     return result;
 }
 
@@ -381,43 +456,13 @@ msFromTime(jsdouble t)
 {
     intN result = (intN) fmod(t, msPerSecond);
     if (result < 0)
-       result += (intN)msPerSecond;
+        result += (intN)msPerSecond;
     return result;
 }
 
-#define MakeTime(hour, min, sec, ms) \
-(((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms)
-
-static jsdouble
-MakeDay(jsdouble year, jsdouble month, jsdouble date)
-{
-    jsdouble result;
-    JSBool leap;
-    jsdouble yearday;
-    jsdouble monthday;
-
-    year += floor(month / 12);
-
-    month = fmod(month, 12.0);
-    if (month < 0)
-       month += 12;
-
-    leap = (DaysInYear((jsint) year) == 366);
-
-    yearday = floor(TimeFromYear(year) / msPerDay);
-    monthday = DayFromMonth(month, leap);
-
-    result = yearday
-            + monthday
-            + date - 1;
-    return result;
-}
-
-#define MakeDate(day, time) (day * msPerDay + time)
-
 #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
-                     && !((d < 0 ? -d : d) > HalfTimeDomain)) \
-                    ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN)
+                      && !((d < 0 ? -d : d) > HalfTimeDomain)) \
+                     ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN)
 
 /**
  * end of ECMA 'support' functions
@@ -464,28 +509,28 @@ static int ttb[] = {
 /* helper for date_parse */
 static JSBool
 date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
-                  int count, int ignoreCase)
+                   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 (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;
+        result = JS_TRUE;
     }
 
     return result;
@@ -494,7 +539,7 @@ date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
 /* 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 min, jsdouble sec, jsdouble msec)
 {
     jsdouble day;
     jsdouble msec_time;
@@ -520,30 +565,30 @@ date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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;
-       }
+        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;
+        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;
+        array[2] = 1;
 
     d = date_msecFromDate(array[0], array[1], array[2],
-                             array[3], array[4], array[5], array[6]);
+                              array[3], array[4], array[5], array[6]);
     d = TIMECLIP(d);
 
     return js_NewNumberValue(cx, d, rval);
@@ -568,115 +613,120 @@ date_parseString(JSString *str, jsdouble *result)
     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;
+        goto syntax;
     while (i < limit) {
-       c = s[i];
-       i++;
-       if (c <= ' ' || c == ',' || c == '-') {
-           if (c == '-' && '0' <= s[i] && s[i] <= '9') {
-             prevc = c;
-           }
-           continue;
-       }
-       if (c == '(') { /* comments) */
-           int depth = 1;
-           while (i < limit) {
-               c = s[i];
-               i++;
-               if (c == '(') depth++;
-               else if (c == ')')
-                   if (--depth <= 0)
-                       break;
-           }
-           continue;
-       }
-       if ('0' <= c && c <= '9') {
-           n = c - '0';
-           while (i < limit && '0' <= (c = s[i]) && c <= '9') {
-               n = n * 10 + c - '0';
-               i++;
-           }
-
-           /* allow TZA before the year, so
-            * 'Wed Nov 05 21:49:11 GMT-0800 1997'
-            * works */
-
-           /* uses of seenplusminus allow : in TZA, so Java
-            * no-timezone style of GMT+4:30 works
-            */
-
-           if ((prevc == '+' || prevc == '-')/*  && year>=0 */) {
-               /* make ':' case below change tzoffset */
-               seenplusminus = JS_TRUE;
-
-               /* offset */
-               if (n < 24)
-                   n = n * 60; /* EG. "GMT-3" */
-               else
-                   n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
-               if (prevc == '+')       /* plus means east of GMT */
-                   n = -n;
-               if (tzoffset != 0 && tzoffset != -1)
-                   goto syntax;
-               tzoffset = n;
-           } else if (n >= 70 ||
-                      (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
-               if (year >= 0)
-                   goto syntax;
-               else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
-                   year = n < 100 ? n + 1900 : n;
-               else
-                   goto syntax;
-           } else if (c == ':') {
-               if (hour < 0)
-                   hour = /*byte*/ n;
-               else if (min < 0)
-                   min = /*byte*/ n;
-               else
-                   goto syntax;
-           } else if (c == '/') {
-               if (mon < 0)
-                   mon = /*byte*/ n-1;
-               else if (mday < 0)
-                   mday = /*byte*/ n;
-               else
-                   goto syntax;
-           } else if (i < limit && c != ',' && c > ' ' && c != '-') {
-               goto syntax;
-           } else if (seenplusminus && n < 60) {  /* handle GMT-3:30 */
-               if (tzoffset < 0)
-                   tzoffset -= n;
-               else
-                   tzoffset += n;
-           } else if (hour >= 0 && min < 0) {
-               min = /*byte*/ n;
-           } else if (min >= 0 && sec < 0) {
-               sec = /*byte*/ n;
-           } else if (mday < 0) {
-               mday = /*byte*/ n;
-           } else {
-               goto syntax;
-           }
-           prevc = 0;
-       } else if (c == '/' || c == ':' || c == '+' || c == '-') {
-           prevc = c;
-       } else {
-           size_t st = i - 1;
-           int k;
-           while (i < limit) {
-               c = s[i];
-               if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
-                   break;
-               i++;
-           }
-           if (i <= st + 1)
-               goto syntax;
-           for (k = (sizeof(wtb)/sizeof(char*)); --k >= 0;)
-               if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
-                   int action = ttb[k];
-                   if (action != 0) {
+        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
@@ -692,37 +742,113 @@ date_parseString(JSString *str, jsdouble *result)
                                     hour += 12;
                                 }
                             }
-                       } else if (action <= 13) { /* month! */
-                           if (mon < 0) {
-                               mon = /*byte*/ (action - 2);
-                           } else {
-                               goto syntax;
-                           }
-                       } else {
-                           tzoffset = action - 10000;
-                       }
-                   }
-                   break;
-               }
-           if (k < 0)
-               goto syntax;
-           prevc = 0;
-       }
+                        } 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;
+        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;
+        sec = 0;
     if (min < 0)
-       min = 0;
+        min = 0;
     if (hour < 0)
-       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);
+        jsdouble msec_time;
+        msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
 
-       *result = UTC(msec_time);
-       return JS_TRUE;
+        *result = UTC(msec_time);
+        return JS_TRUE;
     }
 
     msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
@@ -744,10 +870,10 @@ date_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
     str = js_ValueToString(cx, argv[0]);
     if (!str)
-       return JS_FALSE;
+        return JS_FALSE;
     if (!date_parseString(str, &result)) {
-       *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
-       return JS_TRUE;
+        *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+        return JS_TRUE;
     }
 
     result = TIMECLIP(result);
@@ -776,7 +902,7 @@ static jsdouble *
 date_getProlog(JSContext *cx, JSObject *obj, jsval *argv)
 {
     if (!JS_InstanceOf(cx, obj, &date_class, argv))
-       return NULL;
+        return NULL;
     return JSVAL_TO_DOUBLE(OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE));
 }
 
@@ -788,7 +914,7 @@ 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_FALSE;
 
     return js_NewNumberValue(cx, *date, rval);
 }
@@ -796,14 +922,17 @@ date_getTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 static JSBool
 date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
+    jsdouble *date;
     jsdouble result;
-    jsdouble *date = date_getProlog(cx, obj, argv);
+    JSVersion version;
+
+    date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
-    result = *date;
+        return JS_FALSE;
 
+    result = *date;
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = YearFromTime(LocalTime(result));
 
@@ -816,9 +945,10 @@ date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
      * the getFullYear method.  But we try to protect existing scripts that
      * have specified a version...
      */
-    if (cx->version == JSVERSION_1_0 ||
-        cx->version == JSVERSION_1_1 ||
-        cx->version == JSVERSION_1_2)
+    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;
@@ -830,16 +960,16 @@ date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
 static JSBool
 date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                jsval *rval)
+                 jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = YearFromTime(LocalTime(result));
     return js_NewNumberValue(cx, result, rval);
@@ -847,16 +977,16 @@ date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                   jsval *rval)
+                    jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = YearFromTime(result);
     return js_NewNumberValue(cx, result, rval);
@@ -864,16 +994,16 @@ date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+              jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = MonthFromTime(LocalTime(result));
     return js_NewNumberValue(cx, result, rval);
@@ -881,16 +1011,16 @@ date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getUTCMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                jsval *rval)
+                 jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = MonthFromTime(result);
     return js_NewNumberValue(cx, result, rval);
@@ -902,11 +1032,11 @@ 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;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = LocalTime(result);
     result = DateFromTime(result);
@@ -915,16 +1045,16 @@ date_getDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
 static JSBool
 date_getUTCDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-               jsval *rval)
+                jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = DateFromTime(result);
     return js_NewNumberValue(cx, result, rval);
@@ -936,11 +1066,11 @@ 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;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = LocalTime(result);
     result = WeekDay(result);
@@ -949,16 +1079,16 @@ date_getDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
 static JSBool
 date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-              jsval *rval)
+               jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = WeekDay(result);
     return js_NewNumberValue(cx, result, rval);
@@ -966,16 +1096,16 @@ date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+              jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = HourFromTime(LocalTime(result));
     return js_NewNumberValue(cx, result, rval);
@@ -983,16 +1113,16 @@ date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                jsval *rval)
+                 jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = HourFromTime(result);
     return js_NewNumberValue(cx, result, rval);
@@ -1000,16 +1130,16 @@ date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-               jsval *rval)
+                jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = MinFromTime(LocalTime(result));
     return js_NewNumberValue(cx, result, rval);
@@ -1017,16 +1147,16 @@ date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                  jsval *rval)
+                   jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = MinFromTime(result);
     return js_NewNumberValue(cx, result, rval);
@@ -1036,16 +1166,16 @@ date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-               jsval *rval)
+                jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = SecFromTime(result);
     return js_NewNumberValue(cx, result, rval);
@@ -1055,16 +1185,16 @@ date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                    jsval *rval)
+                     jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     if (!JSDOUBLE_IS_FINITE(result))
-       return js_NewNumberValue(cx, result, rval);
+        return js_NewNumberValue(cx, result, rval);
 
     result = msFromTime(result);
     return js_NewNumberValue(cx, result, rval);
@@ -1072,12 +1202,12 @@ date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_getTimezoneOffset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                      jsval *rval)
+                       jsval *rval)
 {
     jsdouble result;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     result = *date;
 
     /*
@@ -1095,10 +1225,10 @@ 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;
+        return JS_FALSE;
 
     if (!js_ValueToNumber(cx, argv[0], &result))
-       return JS_FALSE;
+        return JS_FALSE;
 
     result = TIMECLIP(result);
 
@@ -1108,7 +1238,7 @@ date_setTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
 static JSBool
 date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             uintN maxargs, JSBool local, jsval *rval)
+              uintN maxargs, JSBool local, jsval *rval)
 {
     uintN i;
     jsdouble args[4], *argp, *stop;
@@ -1120,13 +1250,13 @@ date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        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);
+        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
@@ -1137,46 +1267,46 @@ date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
      * d.setMilliseconds()" returns NaN.  Blech.
      */
     if (argc == 0)
-       argc = 1;   /* should be safe, because length of all setters is 1 */
+        argc = 1;   /* should be safe, because length of all setters is 1 */
     else if (argc > maxargs)
-       argc = maxargs;  /* clamp argc */
+        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 (!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);
+        lorutime = LocalTime(result);
     else
-       lorutime = result;
+        lorutime = result;
 
     argp = args;
     stop = argp + argc;
     if (maxargs >= 4 && argp < stop)
-       hour = *argp++;
+        hour = *argp++;
     else
-       hour = HourFromTime(lorutime);
+        hour = HourFromTime(lorutime);
 
     if (maxargs >= 3 && argp < stop)
-       min = *argp++;
+        min = *argp++;
     else
-       min = MinFromTime(lorutime);
+        min = MinFromTime(lorutime);
 
     if (maxargs >= 2 && argp < stop)
-       sec = *argp++;
+        sec = *argp++;
     else
-       sec = SecFromTime(lorutime);
+        sec = SecFromTime(lorutime);
 
     if (maxargs >= 1 && argp < stop)
-       msec = *argp;
+        msec = *argp;
     else
-       msec = msFromTime(lorutime);
+        msec = msFromTime(lorutime);
 
     msec_time = MakeTime(hour, min, sec, msec);
     result = MakeDate(Day(lorutime), msec_time);
@@ -1184,7 +1314,7 @@ date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 /*     fprintf(stderr, "%f\n", result); */
 
     if (local)
-       result = UTC(result);
+        result = UTC(result);
 
 /*     fprintf(stderr, "%f\n", result); */
 
@@ -1194,63 +1324,63 @@ date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_setMilliseconds(JSContext *cx, JSObject *obj, uintN argc,
-                    jsval *argv, jsval *rval)
+                     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)
+                        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)
+                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)
+                   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)
+                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)
+                   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)
+              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)
+                 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)
+              jsval *argv, uintN maxargs, JSBool local, jsval *rval)
 {
     uintN i;
     jsdouble lorutime; /* local or UTC version of *date */
@@ -1260,62 +1390,62 @@ date_makeDate(JSContext *cx, JSObject *obj, uintN argc,
 
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        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 */
+        argc = 1;   /* should be safe, because length of all setters is 1 */
     else if (argc > maxargs)
-       argc = maxargs;   /* clamp argc */
+        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 (!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.;
+        if (argc < 3)
+            return js_NewNumberValue(cx, result, rval);
+        else
+            lorutime = +0.;
     } else {
-       if (local)
-           lorutime = LocalTime(result);
-       else
-           lorutime = result;
+        if (local)
+            lorutime = LocalTime(result);
+        else
+            lorutime = result;
     }
 
     argp = args;
     stop = argp + argc;
     if (maxargs >= 3 && argp < stop)
-       year = *argp++;
+        year = *argp++;
     else
-       year = YearFromTime(lorutime);
+        year = YearFromTime(lorutime);
 
     if (maxargs >= 2 && argp < stop)
-       month = *argp++;
+        month = *argp++;
     else
-       month = MonthFromTime(lorutime);
+        month = MonthFromTime(lorutime);
 
     if (maxargs >= 1 && argp < stop)
-       day = *argp++;
+        day = *argp++;
     else
-       day = DateFromTime(lorutime);
+        day = DateFromTime(lorutime);
 
     day = MakeDay(year, month, day); /* day within year */
     result = MakeDate(day, TimeWithinDay(lorutime));
 
     if (local)
-       result = UTC(result);
+        result = UTC(result);
 
     *date = TIMECLIP(result);
     return js_NewNumberValue(cx, *date, rval);
@@ -1323,49 +1453,49 @@ date_makeDate(JSContext *cx, JSObject *obj, uintN argc,
 
 static JSBool
 date_setDate(JSContext *cx, JSObject *obj, uintN argc,
-            jsval *argv, jsval *rval)
+             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)
+                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)
+              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)
+                 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)
+                 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)
+                    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)
+             jsval *argv, jsval *rval)
 {
     jsdouble t;
     jsdouble year;
@@ -1374,27 +1504,27 @@ date_setYear(JSContext *cx, JSObject *obj, uintN argc,
 
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
 
     result = *date;
 
     if (!js_ValueToNumber(cx, argv[0], &year))
-       return JS_FALSE;
+        return JS_FALSE;
     if (!JSDOUBLE_IS_FINITE(year)) {
-       *date = *cx->runtime->jsNaN;
-       return js_NewNumberValue(cx, *date, rval);
+        *date = *cx->runtime->jsNaN;
+        return js_NewNumberValue(cx, *date, rval);
     }
 
     year = js_DoubleToInteger(year);
 
     if (!JSDOUBLE_IS_FINITE(result)) {
-       t = +0.0;
+        t = +0.0;
     } else {
-       t = LocalTime(result);
+        t = LocalTime(result);
     }
 
     if (year >= 0 && year <= 99)
-       year += 1900;
+        year += 1900;
 
     day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
     result = MakeDate(day, TimeWithinDay(t));
@@ -1417,34 +1547,34 @@ static const char* months[] =
 
 static JSBool
 date_toGMTString(JSContext *cx, JSObject *obj, uintN argc,
-                jsval *argv, jsval *rval)
+                 jsval *argv, jsval *rval)
 {
     char buf[100];
     JSString *str;
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
 
     if (!JSDOUBLE_IS_FINITE(*date)) {
-       JS_snprintf(buf, sizeof buf, js_NaN_date_str);
+        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));
+        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;
+        return JS_FALSE;
     *rval = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
@@ -1461,22 +1591,22 @@ new_explode(jsdouble timeval, PRMJTime *split, JSBool findEquivalent)
 
     /* 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;
+        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);
-       }
+            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;
+        adjustedYear = (int16)year;
     }
 
     split->tm_usec = (int32) msFromTime(timeval) * 1000;
@@ -1510,29 +1640,29 @@ date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
     PRMJTime split;
 
     if (!JSDOUBLE_IS_FINITE(date)) {
-       JS_snprintf(buf, sizeof buf, js_NaN_date_str);
+        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);
+        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.
@@ -1607,35 +1737,35 @@ date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
 
     str = JS_NewStringCopyZ(cx, buf);
     if (!str)
-       return JS_FALSE;
+        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)
+                    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;
+        return JS_FALSE;
 
     if (!JSDOUBLE_IS_FINITE(*date)) {
-       JS_snprintf(buf, sizeof buf, js_NaN_date_str);
+        JS_snprintf(buf, sizeof buf, js_NaN_date_str);
     } else {
-       intN result_len;
-       jsdouble local = LocalTime(*date);
-       new_explode(local, &split, JS_FALSE);
+        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);
+        /* 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);
+        /* 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] == '/' &&
@@ -1647,18 +1777,18 @@ date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc,
     }
 
     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
-       return cx->localeCallbacks->localeToUnicode(cx, buf, rval);
-    
+        return cx->localeCallbacks->localeToUnicode(cx, buf, rval);
+
     str = JS_NewStringCopyZ(cx, buf);
     if (!str)
-       return JS_FALSE;
+        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)
+                    jsval *argv, jsval *rval)
 {
     /* Use '%#c' for windows, because '%c' is
      * backward-compatible and non-y2k with msvc; '%#c' requests that a
@@ -1666,16 +1796,16 @@ date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
      */
     return date_toLocaleHelper(cx, obj, argc, argv, rval,
 #if defined(_WIN32) && !defined(__MWERKS__)
-                                  "%#c"
+                                   "%#c"
 #else
-                                  "%c"
+                                   "%c"
 #endif
-                                  );
+                                   );
 }
 
 static JSBool
 date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc,
-                   jsval *argv, jsval *rval)
+                    jsval *argv, jsval *rval)
 {
     /* Use '%#x' for windows, because '%x' is
      * backward-compatible and non-y2k with msvc; '%#x' requests that a
@@ -1683,37 +1813,54 @@ date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc,
      */
     return date_toLocaleHelper(cx, obj, argc, argv, rval,
 #if defined(_WIN32) && !defined(__MWERKS__)
-                                  "%#x"
+                                   "%#x"
 #else
-                                  "%x"
+                                   "%x"
 #endif
-                                  );
+                                   );
 }
 
 static JSBool
 date_toLocaleTimeString(JSContext *cx, JSObject *obj, uintN argc,
-                   jsval *argv, jsval *rval)
+                        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)
+                  jsval *argv, jsval *rval)
 {
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        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)
+                  jsval *argv, jsval *rval)
 {
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
     return date_format(cx, *date, FORMATSPEC_DATE, rval);
 }
 
@@ -1723,7 +1870,7 @@ date_toDateString(JSContext *cx, JSObject *obj, uintN argc,
 
 static JSBool
 date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+              jsval *rval)
 {
     jsdouble *date;
     char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes;
@@ -1731,24 +1878,24 @@ date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
     date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        return JS_FALSE;
 
     numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, *date);
     if (!numStr) {
-       JS_ReportOutOfMemory(cx);
-       return JS_FALSE;
+        JS_ReportOutOfMemory(cx);
+        return JS_FALSE;
     }
 
     bytes = JS_smprintf("(new %s(%s))", date_class.name, numStr);
     if (!bytes) {
-       JS_ReportOutOfMemory(cx);
-       return JS_FALSE;
+        JS_ReportOutOfMemory(cx);
+        return JS_FALSE;
     }
 
     str = JS_NewString(cx, bytes, strlen(bytes));
     if (!str) {
-       free(bytes);
-       return JS_FALSE;
+        free(bytes);
+        return JS_FALSE;
     }
     *rval = STRING_TO_JSVAL(str);
     return JS_TRUE;
@@ -1757,18 +1904,18 @@ date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSBool
 date_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+              jsval *rval)
 {
     jsdouble *date = date_getProlog(cx, obj, argv);
     if (!date)
-       return JS_FALSE;
+        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)
+             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
@@ -1777,18 +1924,18 @@ date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
     /* If called directly with no arguments, convert to a time number. */
     if (argc == 0)
-       return date_getTime(cx, obj, argc, argv, rval);
+        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);
+        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);
 }
@@ -1848,6 +1995,7 @@ static JSFunctionSpec date_methods[] = {
     {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
@@ -1863,9 +2011,9 @@ date_constructor(JSContext *cx, JSObject* obj)
 {
     jsdouble *date;
 
-    date = js_NewDouble(cx, 0.0);
+    date = js_NewDouble(cx, 0.0, 0);
     if (!date)
-       return NULL;
+        return NULL;
     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, DOUBLE_TO_JSVAL(date));
     return date;
 }
@@ -1877,103 +2025,103 @@ Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     JSString *str;
     jsdouble d;
 
-    /* Date called as function */
+    /* 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);
+        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 */
+    /* Date called as constructor. */
     if (argc == 0) {
-       int64 us, ms, us2ms;
-       jsdouble msec_time;
+        int64 us, ms, us2ms;
+        jsdouble msec_time;
 
-       date = date_constructor(cx, obj);
-       if (!date)
-           return JS_FALSE;
+        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);
+        us = PRMJ_Now();
+        JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
+        JSLL_DIV(ms, us, us2ms);
+        JSLL_L2D(msec_time, ms);
 
-       *date = msec_time;
+        *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);
-       }
+        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 {
+        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);
+            }
+        }
+
+        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;
 }
@@ -1987,9 +2135,9 @@ js_InitDateClass(JSContext *cx, JSObject *obj)
     /* set static LocalTZA */
     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
     proto = JS_InitClass(cx, obj, NULL, &date_class, Date, MAXARGS,
-                        NULL, date_methods, NULL, date_static_methods);
+                         NULL, date_methods, NULL, date_static_methods);
     if (!proto)
-       return NULL;
+        return NULL;
 
     /* Alias toUTCString with toGMTString.  (ECMA B.2.6) */
     if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString"))
@@ -1998,7 +2146,7 @@ js_InitDateClass(JSContext *cx, JSObject *obj)
     /* Set the value of the Date.prototype date to NaN */
     proto_date = date_constructor(cx, proto);
     if (!proto_date)
-       return NULL;
+        return NULL;
     *proto_date = *cx->runtime->jsNaN;
 
     return proto;
@@ -2012,11 +2160,11 @@ js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
 
     obj = js_NewObject(cx, &date_class, NULL, NULL);
     if (!obj)
-       return NULL;
+        return NULL;
 
     date = date_constructor(cx, obj);
     if (!date)
-       return NULL;
+        return NULL;
 
     *date = msec_time;
     return obj;
@@ -2052,7 +2200,7 @@ js_DateGetYear(JSContext *cx, JSObject* obj)
 
     /* Preserve legacy API behavior of returning 0 for invalid dates. */
     if (!date || JSDOUBLE_IS_NaN(*date))
-       return 0;
+        return 0;
     return (int) YearFromTime(LocalTime(*date));
 }
 
@@ -2062,7 +2210,7 @@ js_DateGetMonth(JSContext *cx, JSObject* obj)
     jsdouble *date = date_getProlog(cx, obj, NULL);
 
     if (!date || JSDOUBLE_IS_NaN(*date))
-       return 0;
+        return 0;
     return (int) MonthFromTime(LocalTime(*date));
 }
 
@@ -2072,7 +2220,7 @@ js_DateGetDate(JSContext *cx, JSObject* obj)
     jsdouble *date = date_getProlog(cx, obj, NULL);
 
     if (!date || JSDOUBLE_IS_NaN(*date))
-       return 0;
+        return 0;
     return (int) DateFromTime(LocalTime(*date));
 }
 
@@ -2082,7 +2230,7 @@ js_DateGetHours(JSContext *cx, JSObject* obj)
     jsdouble *date = date_getProlog(cx, obj, NULL);
 
     if (!date || JSDOUBLE_IS_NaN(*date))
-       return 0;
+        return 0;
     return (int) HourFromTime(LocalTime(*date));
 }
 
@@ -2092,7 +2240,7 @@ js_DateGetMinutes(JSContext *cx, JSObject* obj)
     jsdouble *date = date_getProlog(cx, obj, NULL);
 
     if (!date || JSDOUBLE_IS_NaN(*date))
-       return 0;
+        return 0;
     return (int) MinFromTime(LocalTime(*date));
 }
 
@@ -2102,7 +2250,7 @@ js_DateGetSeconds(JSContext *cx, JSObject* obj)
     jsdouble *date = date_getProlog(cx, obj, NULL);
 
     if (!date || JSDOUBLE_IS_NaN(*date))
-       return 0;
+        return 0;
     return (int) SecFromTime(*date);
 }
 
@@ -2112,18 +2260,18 @@ js_DateSetYear(JSContext *cx, JSObject *obj, int year)
     jsdouble local;
     jsdouble *date = date_getProlog(cx, obj, NULL);
     if (!date)
-       return;
+        return;
     local = LocalTime(*date);
     /* reset date if it was NaN */
     if (JSDOUBLE_IS_NaN(local))
-       local = 0;
+        local = 0;
     local = date_msecFromDate(year,
-                             MonthFromTime(local),
-                             DateFromTime(local),
-                             HourFromTime(local),
-                             MinFromTime(local),
-                             SecFromTime(local),
-                             msFromTime(local));
+                              MonthFromTime(local),
+                              DateFromTime(local),
+                              HourFromTime(local),
+                              MinFromTime(local),
+                              SecFromTime(local),
+                              msFromTime(local));
     *date = UTC(local);
 }
 
@@ -2133,18 +2281,18 @@ js_DateSetMonth(JSContext *cx, JSObject *obj, int month)
     jsdouble local;
     jsdouble *date = date_getProlog(cx, obj, NULL);
     if (!date)
-       return;
+        return;
     local = LocalTime(*date);
     /* bail if date was NaN */
     if (JSDOUBLE_IS_NaN(local))
-       return;
+        return;
     local = date_msecFromDate(YearFromTime(local),
-                             month,
-                             DateFromTime(local),
-                             HourFromTime(local),
-                             MinFromTime(local),
-                             SecFromTime(local),
-                             msFromTime(local));
+                              month,
+                              DateFromTime(local),
+                              HourFromTime(local),
+                              MinFromTime(local),
+                              SecFromTime(local),
+                              msFromTime(local));
     *date = UTC(local);
 }
 
@@ -2154,17 +2302,17 @@ js_DateSetDate(JSContext *cx, JSObject *obj, int date)
     jsdouble local;
     jsdouble *datep = date_getProlog(cx, obj, NULL);
     if (!datep)
-       return;
+        return;
     local = LocalTime(*datep);
     if (JSDOUBLE_IS_NaN(local))
-       return;
+        return;
     local = date_msecFromDate(YearFromTime(local),
-                             MonthFromTime(local),
-                             date,
-                             HourFromTime(local),
-                             MinFromTime(local),
-                             SecFromTime(local),
-                             msFromTime(local));
+                              MonthFromTime(local),
+                              date,
+                              HourFromTime(local),
+                              MinFromTime(local),
+                              SecFromTime(local),
+                              msFromTime(local));
     *datep = UTC(local);
 }
 
@@ -2174,17 +2322,17 @@ js_DateSetHours(JSContext *cx, JSObject *obj, int hours)
     jsdouble local;
     jsdouble *date = date_getProlog(cx, obj, NULL);
     if (!date)
-       return;
+        return;
     local = LocalTime(*date);
     if (JSDOUBLE_IS_NaN(local))
-       return;
+        return;
     local = date_msecFromDate(YearFromTime(local),
-                             MonthFromTime(local),
-                             DateFromTime(local),
-                             hours,
-                             MinFromTime(local),
-                             SecFromTime(local),
-                             msFromTime(local));
+                              MonthFromTime(local),
+                              DateFromTime(local),
+                              hours,
+                              MinFromTime(local),
+                              SecFromTime(local),
+                              msFromTime(local));
     *date = UTC(local);
 }
 
@@ -2194,17 +2342,17 @@ js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes)
     jsdouble local;
     jsdouble *date = date_getProlog(cx, obj, NULL);
     if (!date)
-       return;
+        return;
     local = LocalTime(*date);
     if (JSDOUBLE_IS_NaN(local))
-       return;
+        return;
     local = date_msecFromDate(YearFromTime(local),
-                             MonthFromTime(local),
-                             DateFromTime(local),
-                             HourFromTime(local),
-                             minutes,
-                             SecFromTime(local),
-                             msFromTime(local));
+                              MonthFromTime(local),
+                              DateFromTime(local),
+                              HourFromTime(local),
+                              minutes,
+                              SecFromTime(local),
+                              msFromTime(local));
     *date = UTC(local);
 }
 
@@ -2214,17 +2362,17 @@ js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds)
     jsdouble local;
     jsdouble *date = date_getProlog(cx, obj, NULL);
     if (!date)
-       return;
+        return;
     local = LocalTime(*date);
     if (JSDOUBLE_IS_NaN(local))
-       return;
+        return;
     local = date_msecFromDate(YearFromTime(local),
-                             MonthFromTime(local),
-                             DateFromTime(local),
-                             HourFromTime(local),
-                             MinFromTime(local),
-                             seconds,
-                             msFromTime(local));
+                              MonthFromTime(local),
+                              DateFromTime(local),
+                              HourFromTime(local),
+                              MinFromTime(local),
+                              seconds,
+                              msFromTime(local));
     *date = UTC(local);
 }
 
index 790b4daf64f8f35b764422416b369027861b1b0e..343314fab3f9d6e6469369c8a78a3acc4f7743ac 100644 (file)
@@ -65,7 +65,7 @@ js_NewDateObjectMsec(JSContext* cx, jsdouble msec_time);
  */
 extern JS_FRIEND_API(JSObject*)
 js_NewDateObject(JSContext* cx, int year, int mon, int mday,
-                               int hour, int min, int sec);
+                 int hour, int min, int sec);
 
 /*
  * Detect whether the internal date value is NaN.  (Because failure is
index 8713a86b99fd03cbaa48c0978dd1036aa5cacd80..cddbd480865bfe3c8ad78784a21078155b8ada42 100644 (file)
@@ -278,14 +278,18 @@ DropWatchPoint(JSContext *cx, JSWatchPoint *wp)
 }
 
 void
-js_MarkWatchPoints(JSRuntime *rt)
+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);
     }
 }
 
@@ -335,7 +339,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
     JSRuntime *rt;
     JSWatchPoint *wp;
     JSScopeProperty *sprop;
-    jsval userid;
+    jsval propid, userid;
     JSScope *scope;
     JSBool ok;
 
@@ -346,11 +350,14 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
         sprop = wp->sprop;
         if (wp->object == obj && SPROP_USERID(sprop) == id) {
             JS_LOCK_OBJ(cx, obj);
-            userid = SPROP_USERID(sprop);
+            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, userid,
+            ok = wp->handler(cx, obj, propid,
                              SPROP_HAS_VALID_SLOT(sprop, scope)
                              ? OBJ_GET_SLOT(cx, obj, wp->sprop->slot)
                              : JSVAL_VOID,
@@ -361,14 +368,58 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
                  * stack-walking security code in the setter will correctly
                  * identify the guilty party.
                  */
-                JSObject *funobj = (JSObject *) wp->closure;
-                JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, funobj);
+                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 = FUN_SCRIPT(fun);
+                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)
@@ -376,6 +427,8 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
                                         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);
         }
@@ -393,6 +446,7 @@ js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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];
@@ -408,12 +462,14 @@ js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
     if (!(attrs & JSPROP_SETTER))
         return &js_watch_set;   /* & to silence schoolmarmish MSVC */
 
-    if (!JSVAL_IS_INT(id)) {
-        atom = (JSAtom *)id;
-    } else {
-        atom = js_AtomizeInt(cx, JSVAL_TO_INT(id), 0);
+    if (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),
@@ -444,13 +500,13 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
     }
 
     if (JSVAL_IS_INT(id)) {
-        propid = (jsid)id;
+        propid = INT_JSVAL_TO_JSID(id);
         atom = NULL;
     } else {
         atom = js_ValueToStringAtom(cx, id);
         if (!atom)
             return JS_FALSE;
-        propid = (jsid)atom;
+        propid = ATOM_TO_JSID(atom);
     }
 
     if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
@@ -473,7 +529,8 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
         /* Clone the prototype property so we can watch the right object. */
         jsval value;
         JSPropertyOp getter, setter;
-        uintN attrs;
+        uintN attrs, flags;
+        intN shortid;
 
         if (OBJ_IS_NATIVE(pobj)) {
             value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
@@ -482,18 +539,23 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
             getter = sprop->getter;
             setter = sprop->setter;
             attrs = sprop->attrs;
+            flags = sprop->flags;
+            shortid = sprop->shortid;
         } else {
-            if (!OBJ_GET_PROPERTY(cx, pobj, id, &value)) {
+            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 = JS_PropertyStub;
-            attrs = JSPROP_ENUMERATE;
+            getter = setter = NULL;
+            flags = 0;
+            shortid = 0;
         }
         OBJ_DROP_PROPERTY(cx, pobj, prop);
 
-        if (!js_DefineProperty(cx, obj, propid, value, getter, setter, attrs,
-                               &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;
@@ -524,10 +586,8 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
             JS_free(cx, wp);
             goto out;
         }
-        JS_APPEND_LINK(&wp->links, &rt->watchPointList);
         wp->object = obj;
-        wp->sprop = sprop;
-        JS_ASSERT(sprop->setter != js_watch_set);
+        JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
         wp->setter = sprop->setter;
         wp->nrefs = 1;
 
@@ -535,10 +595,16 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
         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;
@@ -628,6 +694,12 @@ 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)
 {
@@ -673,12 +745,16 @@ JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
 JS_PUBLIC_API(JSPrincipals *)
 JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
 {
-    if (fp->fun && cx->findObjectPrincipals) {
-        JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]);
+    if (fp->fun) {
+        JSRuntime *rt = cx->runtime;
+
+        if (rt->findObjectPrincipals) {
+            JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]);
 
-        if (fp->fun->object != callee)
-            return cx->findObjectPrincipals(cx, callee);
-        /* FALL THROUGH */
+            if (fp->fun->object != callee)
+                return rt->findObjectPrincipals(cx, callee);
+            /* FALL THROUGH */
+        }
     }
     if (fp->script)
         return fp->script->principals;
@@ -688,11 +764,24 @@ JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
 JS_PUBLIC_API(JSPrincipals *)
 JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
 {
-    if (cx->findObjectPrincipals)
-        return cx->findObjectPrincipals(cx, JSVAL_TO_OBJECT(fp->argv[-2]));
+    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 NULL;
-    return JS_StackFramePrincipals(cx, caller);
+        return principals;
+    callerPrincipals = JS_StackFramePrincipals(cx, caller);
+    return (callerPrincipals && principals &&
+            callerPrincipals->subsume(callerPrincipals, principals))
+           ? principals
+           : callerPrincipals;
 }
 
 JS_PUBLIC_API(void *)
@@ -796,6 +885,12 @@ 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)
 {
@@ -837,7 +932,7 @@ JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
 JS_PUBLIC_API(JSVersion)
 JS_GetScriptVersion(JSContext *cx, JSScript *script)
 {
-    return script->version;
+    return script->version & JSVERSION_MASK;
 }
 
 /***************************************************************************/
@@ -865,7 +960,7 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
                           const char *filename, uintN lineno,
                           jsval *rval)
 {
-    uint32 flags;
+    uint32 flags, options;
     JSScript *script;
     JSBool ok;
 
@@ -875,10 +970,13 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
      */
     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;
 
@@ -890,14 +988,15 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
-                        const char *bytes, uintN length,
+                        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);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return JS_FALSE;
     ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
@@ -1258,3 +1357,49 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
 
     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;
+}
index 90215a275de21fd60481ad94da621967cb8b6c54..d1b13d9d4f3d07f5cfe9286478bcdbff1f136ac9 100644 (file)
@@ -53,14 +53,14 @@ 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);
+           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);
+             JSTrapHandler *handlerp, void **closurep);
 
 extern JS_PUBLIC_API(void)
 JS_ClearScriptTraps(JSContext *cx, JSScript *script);
@@ -81,11 +81,11 @@ 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);
+                 JSWatchPointHandler handler, void *closure);
 
 extern JS_PUBLIC_API(JSBool)
 JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
-                  JSWatchPointHandler *handlerp, void **closurep);
+                   JSWatchPointHandler *handlerp, void **closurep);
 
 extern JS_PUBLIC_API(JSBool)
 JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj);
@@ -99,7 +99,7 @@ JS_ClearAllWatchPoints(JSContext *cx);
  * header file "jsconfig.h" has been included.
  */
 extern void
-js_MarkWatchPoints(JSRuntime *rt);
+js_MarkWatchPoints(JSContext *cx);
 
 extern JSScopeProperty *
 js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id);
@@ -131,6 +131,9 @@ 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);
 
@@ -164,10 +167,11 @@ extern JS_PUBLIC_API(JSPrincipals *)
 JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp);
 
 /*
- * Like JS_StackFramePrincipals(cx, caller), but if cx->findObjectPrincipals
- * is non-null, return the object principals for fp's callee function object
- * (fp->argv[-2]), which is eval, Function, or a similar eval-like method.
- * The caller parameter should be the result of JS_GetScriptedCaller(cx, fp).
+ * 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
@@ -221,6 +225,12 @@ 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 *)
@@ -250,7 +260,7 @@ JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata);
 
 extern JS_PUBLIC_API(void)
 JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
-                       void *callerdata);
+                        void *callerdata);
 
 /************************************************************************/
 
@@ -262,9 +272,9 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
 
 extern JS_PUBLIC_API(JSBool)
 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
-                       const char *bytes, uintN length,
-                       const char *filename, uintN lineno,
-                       jsval *rval);
+                        const char *bytes, uintN length,
+                        const char *filename, uintN lineno,
+                        jsval *rval);
 
 /************************************************************************/
 
@@ -298,7 +308,7 @@ JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
-                  JSPropertyDesc *pd);
+                   JSPropertyDesc *pd);
 
 extern JS_PUBLIC_API(JSBool)
 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda);
@@ -340,6 +350,57 @@ 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___ */
index abcc36d0516911f701fa42b45bb051d1f8e9161a..cd3006685ad6a5c4f9b0943661533f31e181acc8 100644 (file)
@@ -91,7 +91,7 @@ JS_DHashGetKeyStub(JSDHashTable *table, JSDHashEntryHdr *entry)
 JS_PUBLIC_API(JSDHashNumber)
 JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key)
 {
-    return (JSDHashNumber)key >> 2;
+    return (JSDHashNumber)(unsigned long)key >> 2;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -207,7 +207,9 @@ JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data,
     table->data = data;
     if (capacity < JS_DHASH_MIN_SIZE)
         capacity = JS_DHASH_MIN_SIZE;
-    log2 = JS_CeilingLog2(capacity);
+
+    JS_CEILING_LOG2(log2, capacity);
+
     capacity = JS_BIT(log2);
     if (capacity >= JS_DHASH_SIZE_LIMIT)
         return JS_FALSE;
@@ -601,7 +603,7 @@ JS_PUBLIC_API(uint32)
 JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg)
 {
     char *entryAddr, *entryLimit;
-    uint32 i, capacity, entrySize;
+    uint32 i, capacity, entrySize, ceiling;
     JSBool didRemove;
     JSDHashEntryHdr *entry;
     JSDHashOperator op;
@@ -643,9 +645,11 @@ JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg)
         capacity += capacity >> 1;
         if (capacity < JS_DHASH_MIN_SIZE)
             capacity = JS_DHASH_MIN_SIZE;
-        (void) ChangeTable(table,
-                           JS_CeilingLog2(capacity)
-                           - (JS_DHASH_BITS - table->hashShift));
+
+        JS_CEILING_LOG2(ceiling, capacity);
+        ceiling -= JS_DHASH_BITS - table->hashShift;
+
+        (void) ChangeTable(table, ceiling);
     }
     return i;
 }
index 68f593b1b1e963b56149e4c39f0b7f27c7a530ef..6beecadd120cd7e65f59fefb219f37fe0a797258 100644 (file)
@@ -439,7 +439,7 @@ JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data,
  * we don't shrink on the very next remove after growing a table upon adding
  * an entry that brings entryCount past maxAlpha * tableSize.
  */
-JS_PUBLIC_API(void)
+extern JS_PUBLIC_API(void)
 JS_DHashTableSetAlphaBounds(JSDHashTable *table,
                             float maxAlpha,
                             float minAlpha);
index 9f729fa8ab3f6d9f05b71210662a0fe61dac3f13..ff6731bfaf3e389f7a6cbc3bf2104b2a79365f82 100644 (file)
@@ -228,16 +228,6 @@ static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
 
 #else /* ifndef Bad_float_h */
 #include "float.h"
-/*
- * MacOS 10.2 defines the macro FLT_ROUNDS to an internal function
- * which does not exist on 10.1.  We can safely #define it to 1 here
- * to allow 10.2 builds to run on 10.1, since we can't use fesetround()
- * (which does not exist on 10.1 either).
- */
-#if defined(MACOS_DEPLOYMENT_TARGET) && (MACOS_DEPLOYMENT_TARGET < 100200)
-#undef FLT_ROUNDS   
-#define FLT_ROUNDS 1
-#endif
 #endif /* Bad_float_h */
 
 #ifndef __MATH_H__
@@ -989,7 +979,7 @@ static Bigint *diff(Bigint *a, Bigint *b)
 static double ulp(double x)
 {
     register Long L;
-    double a;
+    double a = 0;
 
     L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
 #ifndef Sudden_Underflow
@@ -1020,7 +1010,7 @@ static double b2d(Bigint *a, int32 *e)
 {
     ULong *xa, *xa0, w, y, z;
     int32 k;
-    double d;
+    double d = 0;
 #define d0 word0(d)
 #define d1 word1(d)
 #define set_d0(x) set_word0(d, x)
@@ -1248,7 +1238,7 @@ JS_strtod(CONST char *s00, char **se, int *err)
 
     *err = 0;
 
-       bb = bd = bs = delta = NULL;
+    bb = bd = bs = delta = NULL;
     sign = nz0 = nz = 0;
     rv = 0.;
 
@@ -2039,7 +2029,7 @@ static int32 quorem(Bigint *b, Bigint *S)
 
 /* 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, 
+ * 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,
@@ -2118,11 +2108,11 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits,
         }
         return JS_TRUE;
     }
-    
+
     b = NULL;                           /* initialize for abort protection */
     S = NULL;
     mlo = mhi = NULL;
-    
+
     if (!d) {
       no_digits:
         *decpt = 1;
@@ -2390,7 +2380,9 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits,
                 goto no_digits;
             goto one_digit;
         }
-        for(i = 1;; i++) {
+
+        /* 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
@@ -2415,8 +2407,7 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits,
                 }
                 break;
             }
-            if (!(d *= 10.))
-                break;
+            d *= 10.;
         }
         goto ret1;
     }
@@ -2829,7 +2820,7 @@ JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, dou
             } while (numEnd != p);
             *numEnd = '\0';
         }
-        
+
         if (exponentialNotation) {
             /* Insert a decimal point if more than one significand digit */
             if (nDigits != 1) {
@@ -2899,7 +2890,7 @@ divrem(Bigint *b, uint32 divisor)
         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);
@@ -2954,7 +2945,7 @@ JS_dtobasestr(int base, double d)
 
         /* 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);
@@ -2995,7 +2986,7 @@ JS_dtobasestr(int base, double d)
             *pInt++ = *q;
             *q-- = ch;
         }
-        
+
         df = d - di;
         if (df != 0.0) {
             /* We have a fraction. */
@@ -3003,7 +2994,7 @@ JS_dtobasestr(int base, double d)
             Bigint *b, *s, *mlo, *mhi;
 
             b = s = mlo = mhi = NULL;
-            
+
             *p++ = '.';
             b = d2b(df, &e, &bbits);
             if (!b) {
@@ -3017,7 +3008,7 @@ JS_dtobasestr(int base, double d)
             }
             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)
index ece00fae1cbd226462e00f965cb843596361d2cf..c7e32f2007815c931920aea30cd58882b6fb7ddb 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
@@ -155,12 +156,15 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
     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_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                             JSMSG_STACK_UNDERFLOW,
-                             cg->filename ? cg->filename : "stdin", numBuf);
+        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)
@@ -310,7 +314,7 @@ ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg)
   offsets) of targets that come after a jump target (for when a jump below
   that target needs to be extended).  We use an AVL tree, implemented using
   recursion, but with some tricky optimizations to its height-balancing code
-  (see http://www.enteract.com/~bradapp/ftp/src/libs/C++/AvlTrees.html).
+  (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
@@ -323,11 +327,10 @@ ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg)
   Note that backpatch chains would present a problem for BuildSpanDepTable,
   which inspects bytecode to build cg->spanDeps on demand, when the first
   short jump offset overflows.  To solve this temporary problem, we emit a
-  proxy bytecode (JSOP_BACKPATCH; JSOP_BACKPATCH_PUSH for jumps that push a
-  result on the interpreter's stack, namely JSOP_GOSUB; or JSOP_BACKPATCH_POP
-  for branch ops) whose nuses/ndefs counts help keep the stack balanced, but
-  whose opcode format distinguishes its backpatch delta immediate operand from
-  a normal jump offset.
+  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)
@@ -542,7 +545,7 @@ BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg)
     const JSCodeSpec *cs;
     ptrdiff_t len, off;
 
-    pc = CG_BASE(cg);
+    pc = CG_BASE(cg) + cg->spanDepTodo;
     end = CG_NEXT(cg);
     while (pc < end) {
         op = (JSOp)*pc;
@@ -607,6 +610,7 @@ BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg)
 #endif /* JS_HAS_SWITCH_STATEMENT */
         }
 
+        JS_ASSERT(len > 0);
         pc += len;
     }
 
@@ -784,7 +788,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
             }
 
             if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) {
-                span = SD_TARGET_OFFSET(sd) - pivot;
+                span = SD_SPAN(sd, pivot);
                 if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) {
                     ptrdiff_t deltaFromTop = 0;
 
@@ -906,7 +910,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
         }
 
         oldpc = base + sd->before;
-        span = SD_TARGET_OFFSET(sd) - pivot;
+        span = SD_SPAN(sd, pivot);
 
         /*
          * If this jump didn't need to be extended, restore its span immediate
@@ -1033,6 +1037,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
                 }
             }
         }
+        cg->main.lastNoteOffset += growth;
 
         /*
          * Fix try/catch notes (O(numTryNotes * log2(numSpanDeps)), but it's
@@ -1108,7 +1113,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
         } else {
             span = GET_JUMP_OFFSET(pc);
         }
-        JS_ASSERT(SD_TARGET_OFFSET(sd) == pivot + span);
+        JS_ASSERT(SD_SPAN(sd, pivot) == span);
     }
     JS_ASSERT(!JOF_TYPE_IS_EXTENDED_JUMP(type) || bigspans != 0);
   }
@@ -1126,22 +1131,23 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
     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;
 
-    if (off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off) {
-        if (!cg->spanDeps && !BuildSpanDepTable(cx, cg))
-            return JS_FALSE;
-    }
+    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 && cg->spanDeps) {
+    if (jmp >= 0 && (extend || cg->spanDeps)) {
         pc = CG_CODE(cg, jmp);
         if (!AddSpanDep(cx, cg, pc, pc, off))
             return JS_FALSE;
@@ -1227,15 +1233,17 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
  * Emit a backpatch op with offset pointing to the previous jump of this type,
  * so that we can walk back up the chain fixing up the op and jump offset.
  */
-#define EMIT_BACKPATCH_OP(cx, cg, last, op, jmp)                              \
-    JS_BEGIN_MACRO                                                            \
-        ptrdiff_t offset, delta;                                              \
-        offset = CG_OFFSET(cg);                                               \
-        delta = offset - (last);                                              \
-        last = offset;                                                        \
-        JS_ASSERT(delta > 0);                                                 \
-        jmp = EmitJump((cx), (cg), (op), (delta));                            \
-    JS_END_MACRO
+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
@@ -1294,7 +1302,7 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
           case STMT_FINALLY:
             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
                 return JS_FALSE;
-            EMIT_BACKPATCH_OP(cx, cg, stmt->gosub, JSOP_BACKPATCH_PUSH, jmp);
+            jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmt->gosub);
             if (jmp < 0)
                 return JS_FALSE;
             break;
@@ -1318,10 +1326,13 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
             break;
 
           case STMT_SUBROUTINE:
-            /* There's a retsub pc-offset on the stack that we need to pop. */
+            /*
+             * 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_POP) < 0)
+            if (js_Emit1(cx, cg, JSOP_POP2) < 0)
                 return JS_FALSE;
             break;
 
@@ -1335,10 +1346,9 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
 
 static ptrdiff_t
 EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
-         ptrdiff_t *last, JSAtomListElement *label, JSSrcNoteType noteType)
+         ptrdiff_t *lastp, JSAtomListElement *label, JSSrcNoteType noteType)
 {
     intN index;
-    ptrdiff_t jmp;
 
     if (!EmitNonLocalJumpFixup(cx, cg, toStmt, NULL))
         return -1;
@@ -1356,8 +1366,7 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
             return -1;
     }
 
-    EMIT_BACKPATCH_OP(cx, cg, *last, JSOP_BACKPATCH, jmp);
-    return jmp;
+    return EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp);
 }
 
 static JSBool
@@ -1473,7 +1482,22 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
              * nor can prop be deleted.
              */
             prop = NULL;
-            ok = OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop);
+            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))) {
@@ -1483,9 +1507,10 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
                      * variable object.  Therefore we can get constant values
                      * from our variable object here.
                      */
-                    ok = OBJ_GET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
+                    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, (jsid)atom, vp);
+                        ok = OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
                 }
                 if (prop)
                     OBJ_DROP_PROPERTY(cx, pobj, prop);
@@ -1586,16 +1611,97 @@ IndexRegExpClone(JSContext *cx, JSParseNode *pn, JSAtomListElement *ale,
 }
 
 /*
- * Emit a bytecode and its 2-byte constant (atom) index immediate operand.
+ * 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 (js_Emit3(cx, cg, op, ATOM_INDEX_HI(atomIndex),                    \
-                                 ATOM_INDEX_LO(atomIndex)) < 0) {             \
+        if (!EmitAtomIndexOp(cx, op, atomIndex, cg))                          \
             return JS_FALSE;                                                  \
-        }                                                                     \
     JS_END_MACRO
 
 static JSBool
@@ -1608,8 +1714,7 @@ EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
         return JS_FALSE;
     if (op == JSOP_REGEXP && !IndexRegExpClone(cx, pn, ale, cg))
         return JS_FALSE;
-    EMIT_ATOM_INDEX_OP(op, ALE_INDEX(ale));
-    return JS_TRUE;
+    return EmitAtomIndexOp(cx, op, ALE_INDEX(ale), cg);
 }
 
 /*
@@ -1646,6 +1751,21 @@ LookupArgOrVar(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
     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.
@@ -1730,7 +1850,7 @@ LookupArgOrVar(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
          * NB: We know that JSOP_DELNAME on an argument or variable evaluates
          * to false, due to JSPROP_PERMANENT.
          */
-        if (!js_LookupProperty(cx, obj, (jsid)atom, &pobj, &prop))
+        if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
             return JS_FALSE;
         sprop = (JSScopeProperty *) prop;
         if (sprop) {
@@ -1954,12 +2074,30 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
     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;
-    JSAtomListElement *ale;
 
     pn2 = pn->pn_expr;
     if (op == JSOP_GETPROP &&
@@ -2000,14 +2138,12 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 
         do {
             /* Walk back up the list, emitting annotated name ops. */
-            if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
+            if (js_NewSrcNote2(cx, cg, SrcNoteForPropOp(pndot, pndot->pn_op),
                                CG_OFFSET(cg) - pndown->pn_offset) < 0) {
                 return JS_FALSE;
             }
-            ale = js_IndexAtom(cx, pndot->pn_atom, &cg->atomList);
-            if (!ale)
+            if (!EmitAtomOp(cx, pndot, pndot->pn_op, cg))
                 return JS_FALSE;
-            EMIT_ATOM_INDEX_OP(pndot->pn_op, ALE_INDEX(ale));
 
             /* Reverse the pn_expr link again. */
             pnup = pndot->pn_expr;
@@ -2019,17 +2155,17 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
             return JS_FALSE;
     }
 
-    if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - pn2->pn_offset) < 0)
+    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 {
-        ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
-        if (!ale)
+        if (!EmitAtomOp(cx, pn, op, cg))
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(op, ALE_INDEX(ale));
     }
     return JS_TRUE;
 }
@@ -2038,7 +2174,7 @@ static JSBool
 EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     ptrdiff_t top;
-    JSParseNode *left, *right, *next;
+    JSParseNode *left, *right, *next, temp;
     jsint slot;
 
     top = CG_OFFSET(cg);
@@ -2060,9 +2196,9 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
                 return JS_FALSE;
             if (left->pn_op == JSOP_ARGUMENTS &&
                 JSDOUBLE_IS_INT(next->pn_dval, slot) &&
-                (jsuint)slot < ATOM_INDEX_LIMIT) {
+                (jsuint)slot < JS_BIT(16)) {
                 left->pn_offset = next->pn_offset = top;
-                EMIT_ATOM_INDEX_OP(JSOP_ARGSUB, (jsatomid)slot);
+                EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
                 left = next;
                 next = left->pn_next;
             }
@@ -2090,9 +2226,22 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
             next = next->pn_next;
         }
     } else {
-        JS_ASSERT(pn->pn_arity == PN_BINARY);
-        left = pn->pn_left;
-        right = pn->pn_right;
+        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 &&
@@ -2102,9 +2251,9 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
                 return JS_FALSE;
             if (left->pn_op == JSOP_ARGUMENTS &&
                 JSDOUBLE_IS_INT(right->pn_dval, slot) &&
-                (jsuint)slot < ATOM_INDEX_LIMIT) {
+                (jsuint)slot < JS_BIT(16)) {
                 left->pn_offset = right->pn_offset = top;
-                EMIT_ATOM_INDEX_OP(JSOP_ARGSUB, (jsatomid)slot);
+                EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
                 return JS_TRUE;
             }
         }
@@ -2124,6 +2273,8 @@ EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg)
 {
     jsint ival;
     jsatomid atomIndex;
+    ptrdiff_t off;
+    jsbytecode *pc;
     JSAtom *atom;
     JSAtomListElement *ale;
 
@@ -2132,22 +2283,33 @@ EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg)
             return js_Emit1(cx, cg, JSOP_ZERO) >= 0;
         if (ival == 1)
             return js_Emit1(cx, cg, JSOP_ONE) >= 0;
-        if ((jsuint)ival < (jsuint)ATOM_INDEX_LIMIT) {
-            atomIndex = (jsatomid)ival;
-            EMIT_ATOM_INDEX_OP(JSOP_UINT16, atomIndex);
+
+        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;
-    EMIT_ATOM_INDEX_OP(JSOP_NUMBER, ALE_INDEX(ale));
-    return JS_TRUE;
+    return EmitAtomIndexOp(cx, JSOP_NUMBER, ALE_INDEX(ale), cg);
 }
 
 #if JS_HAS_SWITCH_STATEMENT
@@ -2375,6 +2537,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
     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) {
@@ -2388,8 +2551,10 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
                     return JS_FALSE;
                 }
             }
-            if (pn3->pn_type == TOK_DEFAULT)
+            if (!pn4) {
+                JS_ASSERT(pn3->pn_type == TOK_DEFAULT);
                 continue;
+            }
             caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
             if (caseNoteIndex < 0)
                 return JS_FALSE;
@@ -2397,12 +2562,13 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
             if (off < 0)
                 return JS_FALSE;
             pn3->pn_offset = off;
-            if (pn3 == pn2->pn_head) {
+            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;
             }
         }
 
@@ -2624,7 +2790,7 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
     fun->u.script = js_NewScriptFromCG(cx, cg, fun);
     if (!fun->u.script)
         return JS_FALSE;
-    fun->interpreted = JS_TRUE;
+    JS_ASSERT(fun->interpreted);
     if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)
         fun->flags |= JSFUN_HEAVYWEIGHT;
     return JS_TRUE;
@@ -2678,7 +2844,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
     JSAtom *atom;
     JSAtomListElement *ale;
     jsatomid atomIndex;
-    intN noteIndex;
+    ptrdiff_t noteIndex;
     JSSrcNoteType noteType;
     jsbytecode *pc;
     JSOp op;
@@ -2704,6 +2870,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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);
@@ -2716,7 +2890,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                                   cg->principals)) {
             return JS_FALSE;
         }
-        cg2->treeContext.flags = pn->pn_flags | TCF_IN_FUNCTION;
+        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));
@@ -2765,25 +2939,43 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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_LookupProperty(cx, obj, (jsid)fun->atom, &pobj,
-                                   &prop)) {
+            if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(fun->atom),
+                                         &pobj, &prop)) {
                 return JS_FALSE;
             }
+
             JS_ASSERT(prop && pobj == obj);
-            slot = ((JSScopeProperty *) prop)->shortid;
+            sprop = (JSScopeProperty *) prop;
+            JS_ASSERT(sprop->getter == js_GetLocalVariable);
+            slot = sprop->shortid;
             OBJ_DROP_PROPERTY(cx, pobj, prop);
 
-            /* Emit [JSOP_DEFLOCALFUN, local variable slot, atomIndex]. */
-            off = js_EmitN(cx, cg, JSOP_DEFLOCALFUN, VARNO_LEN+ATOM_INDEX_LEN);
-            if (off < 0)
-                return JS_FALSE;
-            pc = CG_CODE(cg, off);
-            SET_VARNO(pc, slot);
-            pc += VARNO_LEN;
-            SET_ATOM_INDEX(pc, atomIndex);
+            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);
@@ -2977,6 +3169,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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;
@@ -3018,7 +3212,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             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;
@@ -3048,7 +3249,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                     if (pn3->pn_attrs & JSPROP_READONLY)
                         op = JSOP_GETVAR;
                     atomIndex = (jsatomid) pn3->pn_slot;
-                    EMIT_ATOM_INDEX_OP(op, atomIndex);
+                    EMIT_UINT16_IMM_OP(op, atomIndex);
                 } else {
                     if (!EmitAtomOp(cx, pn3, op, cg))
                         return JS_FALSE;
@@ -3056,10 +3257,24 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                 break;
 
               case TOK_DOT:
-                if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg))
+                useful = JS_TRUE;
+                if (!CheckSideEffects(cx, &cg->treeContext, pn3->pn_expr,
+                                      &useful)) {
                     return JS_FALSE;
-                break;
+                }
+                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
@@ -3067,6 +3282,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                  * 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;
 
@@ -3084,6 +3300,27 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                 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;
@@ -3092,7 +3329,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
               default:
                 JS_ASSERT(0);
             }
-            if (pn3->pn_type != TOK_LB) {
+
+            if (emitIFEQ) {
                 /* Annotate so the decompiler can find the loop-closing jump. */
                 noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
                 if (noteIndex < 0)
@@ -3276,14 +3514,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         /* Quell GCC overwarnings. */
         end = catchStart = finallyCatch = catchJump = -1;
 
-/* Emit JSOP_GOTO that points to the first op after the catch/finally blocks */
-#define EMIT_CATCH_GOTO(cx, cg, jmp)                                          \
-    EMIT_BACKPATCH_OP(cx, cg, stmtInfo.catchJump, JSOP_BACKPATCH, jmp)
-
-/* Emit JSOP_GOSUB that points to the finally block. */
-#define EMIT_FINALLY_GOSUB(cx, cg, jmp)                                       \
-    EMIT_BACKPATCH_OP(cx, cg, stmtInfo.gosub, JSOP_BACKPATCH_PUSH, jmp)
-
         /*
          * Push stmtInfo to track jumps-over-catches and gosubs-to-finally
          * for later fixup.
@@ -3291,7 +3521,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
          * When a finally block is `active' (STMT_FINALLY on the treeContext),
          * non-local jumps (including jumps-over-catches) result in a GOSUB
          * being written into the bytecode stream and fixed-up later (c.f.
-         * EMIT_BACKPATCH_OP and BackPatch).
+         * EmitBackPatchOp and BackPatch).
          */
         js_PushStatement(&cg->treeContext, &stmtInfo,
                          pn->pn_kid3 ? STMT_FINALLY : STMT_BLOCK,
@@ -3321,7 +3551,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         if (pn->pn_kid3) {
             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
                 return JS_FALSE;
-            EMIT_FINALLY_GOSUB(cx, cg, jmp);
+            jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.gosub);
             if (jmp < 0)
                 return JS_FALSE;
         }
@@ -3329,7 +3559,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         /* Emit (hidden) jump over catch and/or finally. */
         if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
             return JS_FALSE;
-        EMIT_CATCH_GOTO(cx, cg, jmp);
+        jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.catchJump);
         if (jmp < 0)
             return JS_FALSE;
 
@@ -3358,7 +3588,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
              *
              * If there's no catch block without a catchguard, the last
              * <offset to next catch block> points to rethrow code.  This
-             * code will GOSUB to the finally code if appropriate, and is
+             * 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.
              */
@@ -3371,9 +3601,15 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                     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);
@@ -3384,7 +3620,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                     }
                 } else {
                     /* Set stack to original depth (see SETSP comment above). */
-                    EMIT_ATOM_INDEX_OP(JSOP_SETSP, (jsatomid)depth);
+                    EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth);
                     cg->stackDepth = depth;
                 }
 
@@ -3457,15 +3693,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
 
                 /* gosub <finally>, if required */
                 if (pn->pn_kid3) {
-                    EMIT_FINALLY_GOSUB(cx, cg, jmp);
+                    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;
-                EMIT_CATCH_GOTO(cx, cg, jmp);
+                jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH,
+                                      &stmtInfo.catchJump);
                 if (jmp < 0)
                     return JS_FALSE;
                 if (!iter->pn_kid2)     /* leave iter at last catch */
@@ -3475,12 +3714,35 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         }
 
         /*
-         * We use a [setsp],[gosub],rethrow block for rethrowing when
-         * there's no unguarded catch, and also for running finally code
-         * while letting an uncaught exception pass through.
+         * 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
@@ -3489,27 +3751,24 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
              * stack fixup.
              */
             finallyCatch = CG_OFFSET(cg);
-            EMIT_ATOM_INDEX_OP(JSOP_SETSP, (jsatomid)depth);
+            EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth);
             cg->stackDepth = depth;
 
-            /* Last discriminant jumps to rethrow if none match. */
-            if (catchJump != -1 && iter->pn_kid1->pn_expr)
-                CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump);
-
             if (pn->pn_kid3) {
-                EMIT_FINALLY_GOSUB(cx, cg, jmp);
+                jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.gosub);
                 if (jmp < 0)
                     return JS_FALSE;
-                cg->stackDepth = depth;
-            }
 
-            if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
-                js_Emit1(cx, cg, JSOP_EXCEPTION) < 0 ||
-                js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
-                js_Emit1(cx, cg, JSOP_THROW) < 0) {
-                return JS_FALSE;
+                JS_ASSERT(cg->stackDepth == depth);
+                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;
+                }
             }
-            JS_ASSERT(cg->stackDepth == depth);
         }
 
         /*
@@ -3521,12 +3780,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                 return JS_FALSE;
 
             /*
-             * The stack budget must be balanced at this point, and we need
-             * one more slot for the JSOP_RETSUB return address pushed by a
-             * JSOP_GOSUB opcode that calls this finally clause.
+             * 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);
-            if ((uintN)++cg->stackDepth > cg->maxStackDepth)
+            cg->stackDepth += 2;
+            if ((uintN)cg->stackDepth > cg->maxStackDepth)
                 cg->maxStackDepth = cg->stackDepth;
 
             /* Now indicate that we're emitting a subroutine body. */
@@ -3538,8 +3799,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                 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;
         }
-        js_PopStatementCG(cx, cg);
+        if (!js_PopStatementCG(cx, cg))
+            return JS_FALSE;
 
         if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
             js_Emit1(cx, cg, JSOP_NOP) < 0) {
@@ -3648,6 +3914,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             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);
             }
@@ -3698,6 +3966,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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))
@@ -3724,7 +4003,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             }
             if (!useful) {
                 CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno;
-                if (!js_ReportCompileErrorNumber(cx, NULL, cg,
+                if (!js_ReportCompileErrorNumber(cx, cg,
+                                                 JSREPORT_CG |
                                                  JSREPORT_WARNING |
                                                  JSREPORT_STRICT,
                                                  JSMSG_USELESS_EXPR)) {
@@ -3843,6 +4123,15 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             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);
@@ -3859,7 +4148,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             switch (pn2->pn_type) {
               case TOK_NAME:
                 if (pn2->pn_op != JSOP_SETNAME) {
-                    EMIT_ATOM_INDEX_OP((pn2->pn_op == JSOP_SETGVAR)
+                    EMIT_UINT16_IMM_OP((pn2->pn_op == JSOP_SETGVAR)
                                        ? JSOP_GETGVAR
                                        : (pn2->pn_op == JSOP_SETARG)
                                        ? JSOP_GETARG
@@ -3876,6 +4165,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
               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;
@@ -3899,17 +4191,22 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         }
 
         /* Left parts such as a.b.c and a[b].c need a decompiler note. */
-        if (pn2->pn_type != TOK_NAME) {
-            if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
-                return JS_FALSE;
+        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);
+                    EMIT_ATOM_INDEX_OP(pn2->pn_op, atomIndex);
+                }
             }
             break;
           case TOK_LB:
@@ -3919,6 +4216,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             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;
@@ -4035,6 +4338,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                     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;
@@ -4047,12 +4360,27 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
 
 #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 +/-. */
-        if (!js_EmitTree(cx, cg, pn->pn_kid))
+        pn2 = pn->pn_kid;
+        if (!js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
-        if (js_Emit1(cx, cg, pn->pn_op) < 0)
+        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;
 
@@ -4062,6 +4390,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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;
@@ -4076,7 +4418,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                          : JSOP_GETVAR;
                 }
                 atomIndex = (jsatomid) pn2->pn_slot;
-                EMIT_ATOM_INDEX_OP(op, atomIndex);
+                EMIT_UINT16_IMM_OP(op, atomIndex);
             } else {
                 if (!EmitAtomOp(cx, pn2, op, cg))
                     return JS_FALSE;
@@ -4101,14 +4443,31 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             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. */
+        /*
+         * 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:
@@ -4128,16 +4487,46 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
             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
@@ -4150,6 +4539,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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
@@ -4165,23 +4557,35 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
          * 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;
 
-        /* Remember start of callable-object bytecode for decompilation hint. */
-        off = pn2->pn_offset;
-
         /*
-         * Push the virtual machine's "obj" register, which was set by a name,
-         * property, or element get (or set) bytecode.
+         * 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
+         * 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.
          */
@@ -4191,6 +4595,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         }
         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;
@@ -4217,25 +4622,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         pn2 = pn->pn_head;
 #if JS_HAS_SHARP_VARS
         if (pn2 && pn2->pn_type == TOK_DEFSHARP) {
-            EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
+            EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
             pn2 = pn2->pn_next;
         }
 #endif
 
-        for (atomIndex = 0; pn2; pn2 = pn2->pn_next) {
-            /* PrimaryExpr enforced ATOM_INDEX_LIMIT, so in-line optimize. */
-            JS_ASSERT(atomIndex < ATOM_INDEX_LIMIT);
-            if (atomIndex == 0) {
-                if (js_Emit1(cx, cg, JSOP_ZERO) < 0)
-                    return JS_FALSE;
-            } else if (atomIndex == 1) {
-                if (js_Emit1(cx, cg, JSOP_ONE) < 0)
-                    return JS_FALSE;
-            } else {
-                EMIT_ATOM_INDEX_OP(JSOP_UINT16, (jsatomid)atomIndex);
-            }
+        for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
+            if (!EmitNumberOp(cx, atomIndex, cg))
+                return JS_FALSE;
 
-            /* Sub-optimal: holes in a sparse initializer are void-filled. */
+            /* 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;
@@ -4243,10 +4639,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
             }
+
             if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
                 return JS_FALSE;
-
-            atomIndex++;
         }
 
         if (pn->pn_extra & PNX_ENDCOMMA) {
@@ -4281,7 +4676,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         pn2 = pn->pn_head;
 #if JS_HAS_SHARP_VARS
         if (pn2 && pn2->pn_type == TOK_DEFSHARP) {
-            EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
+            EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
             pn2 = pn2->pn_next;
         }
 #endif
@@ -4335,11 +4730,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
       case TOK_DEFSHARP:
         if (!js_EmitTree(cx, cg, pn->pn_kid))
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num);
+        EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num);
         break;
 
       case TOK_USESHARP:
-        EMIT_ATOM_INDEX_OP(JSOP_USESHARP, (jsatomid) pn->pn_num);
+        EMIT_UINT16_IMM_OP(JSOP_USESHARP, (jsatomid) pn->pn_num);
         break;
 #endif /* JS_HAS_SHARP_VARS */
 #endif /* JS_HAS_INITIALIZERS */
@@ -4367,10 +4762,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         }
         if (pn->pn_slot >= 0) {
             atomIndex = (jsatomid) pn->pn_slot;
-            EMIT_ATOM_INDEX_OP(op, atomIndex);
+            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:
         /*
@@ -4391,6 +4794,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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;
@@ -4403,6 +4809,148 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
         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);
     }
@@ -4602,7 +5150,7 @@ js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn,
     return sn;
 }
 
-uintN
+JS_FRIEND_API(uintN)
 js_SrcNoteLength(jssrcnote *sn)
 {
     uintN arity;
@@ -4699,7 +5247,7 @@ void DumpSrcNoteSizeHist()
         fp = fopen("/tmp/srcnotes.hist", "w");
         if (!fp)
             return;
-        setlinebuf(fp);
+        setvbuf(fp, NULL, _IONBF, 0);
     }
     fprintf(fp, "SrcNote size histogram:\n");
     for (i = 0; i < NBINS; i++) {
index 3c8c9c6ae18aad2cf331261d1dc10b888550478c..6ec4600b4d972035a53766839aec61fb5cddce54 100644 (file)
@@ -112,6 +112,7 @@ struct JSTreeContext {              /* tree context for semantic checks */
 #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,                                   \
@@ -172,19 +173,26 @@ struct JSJumpTarget {
 #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))
-#define SD_TARGET_OFFSET(sd)    (JS_ASSERT(JT_HAS_TAG((sd)->target)),         \
-                                 JT_CLR_TAG((sd)->target)->offset)
+
+/* 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 */
@@ -195,20 +203,27 @@ struct JSCodeGenerator {
         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 */
@@ -391,13 +406,16 @@ typedef enum JSSrcNoteType {
                                    also used on JSOP_ENDINIT if extra comma
                                    at end of array literal: [1,2,,] */
     SRC_VAR         = 6,        /* JSOP_NAME/SETNAME/FORNAME in a var decl */
-    SRC_PCDELTA     = 7,        /* offset from comma-operator to next POP,
-                                   or from CONDSWITCH to first CASE opcode */
+    SRC_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,       /* offset of first obj.prop.subprop bytecode */
+    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 */
index 6d3a182db1876ebc8a1f54d78d538c1fa247e28b..c637a5630123967b1beea9eb9277b5a6add3a762 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsconfig.h"
+#include "jsdbgapi.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsinterp.h"
-#include "jsopcode.h"
 #include "jsnum.h"
+#include "jsopcode.h"
 #include "jsscript.h"
 
 #if JS_HAS_ERROR_EXCEPTIONS
@@ -92,34 +94,118 @@ typedef struct JSExnPrivate {
     JSErrorReport *errorReport;
 } JSExnPrivate;
 
-/*
- * Undo all the damage done by exn_newPrivate.
- */
-static void
-exn_destroyPrivate(JSContext *cx, JSExnPrivate *privateData)
+static JSErrorReport *
+CopyErrorReport(JSContext *cx, JSErrorReport *report)
 {
-    JSErrorReport *report;
-    const jschar **args;
-
-    if (!privateData)
-        return;
-    report = privateData->errorReport;
-    if (report) {
-        if (report->uclinebuf)
-            JS_free(cx, (void *)report->uclinebuf);
-        if (report->filename)
-            JS_free(cx, (void *)report->filename);
-        if (report->ucmessage)
-            JS_free(cx, (void *)report->ucmessage);
+    /*
+     * 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) {
-            args = report->messageArgs;
-            while (*args != NULL)
-                JS_free(cx, (void *)*args++);
-            JS_free(cx, (void *)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);
         }
-        JS_free(cx, report);
     }
-    JS_free(cx, privateData);
+
+    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;
 }
 
 /*
@@ -128,99 +214,17 @@ exn_destroyPrivate(JSContext *cx, JSExnPrivate *privateData)
 static JSExnPrivate *
 exn_newPrivate(JSContext *cx, JSErrorReport *report)
 {
-    intN i;
     JSExnPrivate *newPrivate;
-    JSErrorReport *newReport;
-    size_t capacity;
 
     newPrivate = (JSExnPrivate *)JS_malloc(cx, sizeof (JSExnPrivate));
     if (!newPrivate)
         return NULL;
-    memset(newPrivate, 0, sizeof (JSExnPrivate));
-
-    /* Copy the error report */
-    newReport = (JSErrorReport *)JS_malloc(cx, sizeof (JSErrorReport));
-    if (!newReport)
-        goto error;
-    memset(newReport, 0, sizeof (JSErrorReport));
-    newPrivate->errorReport = newReport;
-
-    if (report->filename != NULL) {
-        newReport->filename = JS_strdup(cx, report->filename);
-        if (!newReport->filename)
-            goto error;
-    } else {
-        newReport->filename = NULL;
-    }
-
-    newReport->lineno = report->lineno;
-
-    /*
-     * We don't need to copy linebuf and tokenptr, because they
-     * point into the deflated string cache.  (currently?)
-     */
-    newReport->linebuf = report->linebuf;
-    newReport->tokenptr = report->tokenptr;
-
-    /*
-     * But we do need to copy uclinebuf, uctokenptr, because they're
-     * pointers into internal tokenstream structs, and may go away.
-     */
-    if (report->uclinebuf != NULL) {
-        capacity = js_strlen(report->uclinebuf) + 1;
-        newReport->uclinebuf =
-            (const jschar *)JS_malloc(cx, capacity * sizeof(jschar));
-        if (!newReport->uclinebuf)
-            goto error;
-        js_strncpy((jschar *)newReport->uclinebuf, report->uclinebuf, capacity);
-        newReport->uctokenptr = newReport->uclinebuf + (report->uctokenptr -
-                                                        report->uclinebuf);
-    } else {
-        newReport->uclinebuf = newReport->uctokenptr = NULL;
-    }
-
-    if (report->ucmessage != NULL) {
-        capacity = js_strlen(report->ucmessage) + 1;
-        newReport->ucmessage = (const jschar *)
-            JS_malloc(cx, capacity * sizeof(jschar));
-        if (!newReport->ucmessage)
-            goto error;
-        js_strncpy((jschar *)newReport->ucmessage, report->ucmessage, capacity);
-
-        if (report->messageArgs) {
-            for (i = 0; report->messageArgs[i] != NULL; i++)
-                continue;
-            JS_ASSERT(i);
-            newReport->messageArgs =
-                (const jschar **)JS_malloc(cx, (i + 1) * sizeof(jschar *));
-            if (!newReport->messageArgs)
-                goto error;
-            for (i = 0; report->messageArgs[i] != NULL; i++) {
-                capacity = js_strlen(report->messageArgs[i]) + 1;
-                newReport->messageArgs[i] =
-                    (const jschar *)JS_malloc(cx, capacity * sizeof(jschar));
-                if (!newReport->messageArgs[i])
-                    goto error;
-                js_strncpy((jschar *)(newReport->messageArgs[i]),
-                           report->messageArgs[i], capacity);
-            }
-            newReport->messageArgs[i] = NULL;
-        } else {
-            newReport->messageArgs = NULL;
-        }
-    } else {
-        newReport->ucmessage = NULL;
-        newReport->messageArgs = NULL;
+    newPrivate->errorReport = CopyErrorReport(cx, report);
+    if (!newPrivate->errorReport) {
+        JS_free(cx, newPrivate);
+        return NULL;
     }
-    newReport->errorNumber = report->errorNumber;
-
-    /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */
-    newReport->flags = report->flags;
-
     return newPrivate;
-error:
-    exn_destroyPrivate(cx, newPrivate);
-    return NULL;
 }
 
 static void
@@ -233,8 +237,11 @@ exn_finalize(JSContext *cx, JSObject *obj)
 
     if (!JSVAL_IS_VOID(privateValue)) {
         privateData = (JSExnPrivate*) JSVAL_TO_PRIVATE(privateValue);
-        if (privateData)
-            exn_destroyPrivate(cx, privateData);
+        if (privateData) {
+            if (privateData->errorReport)
+                JS_free(cx, privateData->errorReport);
+            JS_free(cx, privateData);
+        }
     }
 }
 
@@ -388,10 +395,15 @@ InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message,
     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_) {                                                      \
@@ -407,8 +419,12 @@ InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message,
     JS_BEGIN_MACRO                                                            \
         JSString *str_ = str;                                                 \
         size_t length_ = JSSTRING_LENGTH(str_);                               \
-        if (stacklen + length_ > stackmax) {                                  \
+        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_) {                                                      \
@@ -425,7 +441,8 @@ InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message,
         if (checkAccess) {
             v = (fp->fun && fp->argv) ? fp->argv[-2] : JSVAL_NULL;
             if (!JSVAL_IS_PRIMITIVE(v)) {
-                ok = checkAccess(cx, fp->fun->object, callerid, JSACC_READ, &v);
+                ok = checkAccess(cx, JSVAL_TO_OBJECT(fp->argv[-2]), callerid,
+                                 JSACC_READ, &v /* ignored */);
                 if (!ok) {
                     ok = JS_TRUE;
                     break;
@@ -487,6 +504,7 @@ InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message,
 
 #undef APPEND_CHAR_TO_STACK
 #undef APPEND_STRING_TO_STACK
+#undef STACK_LENGTH_LIMIT
 
 done:
     if (checkAccess) {
@@ -528,13 +546,27 @@ done:
                              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;
-    jsval pval;
-    int32 lineno;
+    uint32 lineno;
     JSString *message, *filename;
+    JSStackFrame *fp;
 
     if (cx->creatingException)
         return JS_FALSE;
@@ -549,11 +581,12 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
          * prototype ourselves.
          */
         ok = OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(argv[-2]),
-                              (jsid)cx->runtime->atomState.classPrototypeAtom,
-                              &pval);
+                              ATOM_TO_JSID(cx->runtime->atomState
+                                           .classPrototypeAtom),
+                              rval);
         if (!ok)
             goto out;
-        obj = js_NewObject(cx, &ExceptionClass, JSVAL_TO_OBJECT(pval), NULL);
+        obj = js_NewObject(cx, &ExceptionClass, JSVAL_TO_OBJECT(*rval), NULL);
         if (!obj) {
             ok = JS_FALSE;
             goto out;
@@ -588,17 +621,29 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             goto out;
         }
         argv[1] = STRING_TO_JSVAL(filename);
+        fp = NULL;
     } else {
-        filename = cx->runtime->emptyString;
+        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_ValueToInt32(cx, argv[2], &lineno);
+        ok = js_ValueToECMAUint32(cx, argv[2], &lineno);
         if (!ok)
             goto out;
     } else {
-        lineno = 0;
+        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);
@@ -623,9 +668,13 @@ exn_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     jschar *chars, *cp;
     size_t name_length, message_length, length;
 
-    if (!OBJ_GET_PROPERTY(cx, obj, (jsid)cx->runtime->atomState.nameAtom, &v))
+    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;
@@ -669,37 +718,45 @@ exn_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 static JSBool
 exn_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    jsval v;
+    jsval *vp;
     JSString *name, *message, *filename, *lineno_as_str, *result;
-    int32 lineno;
+    uint32 lineno;
     size_t lineno_length, name_length, message_length, filename_length, length;
     jschar *chars, *cp;
 
-    if (!OBJ_GET_PROPERTY(cx, obj, (jsid)cx->runtime->atomState.nameAtom, &v))
+    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, v);
+    }
+    name = js_ValueToString(cx, *rval);
     if (!name)
         return JS_FALSE;
+    *rval = STRING_TO_JSVAL(name);
 
-    if (!JS_GetProperty(cx, obj, js_message_str, &v) ||
-        !(message = js_ValueToSource(cx, v))) {
+    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, &v) ||
-        !(filename = js_ValueToSource(cx, v))) {
+    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, &v) ||
-        !js_ValueToInt32 (cx, v, &lineno)) {
+    if (!JS_GetProperty(cx, obj, js_lineno_str, &vp[2]) ||
+        !js_ValueToECMAUint32 (cx, vp[2], &lineno)) {
         return JS_FALSE;
     }
 
     if (lineno != 0) {
-        if (!(lineno_as_str = js_ValueToString(cx, v))) {
+        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;
@@ -777,7 +834,7 @@ exn_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
 static JSFunctionSpec exception_methods[] = {
 #if JS_HAS_TOSOURCE
-    {js_toSource_str,   exn_toSource,           0,0,0},
+    {js_toSource_str,   exn_toSource,           0,0,3},
 #endif
     {js_toString_str,   exn_toString,           0,0,0},
     {0,0,0,0,0}
@@ -789,6 +846,9 @@ 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;
@@ -803,19 +863,19 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
                                  : NULL,
                                  obj);
         if (!protos[i])
-            return NULL;
+            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)
-            return NULL;
+            break;
 
         /* Make a constructor function for the current name. */
         fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0);
         if (!fun)
-            return NULL;
+            break;
 
         /* Make this constructor make objects of class Exception. */
         fun->clasp = &ExceptionClass;
@@ -823,23 +883,27 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
         /* Make the prototype and constructor links. */
         if (!js_SetClassPrototype(cx, fun->object, protos[i],
                                   JSPROP_READONLY | JSPROP_PERMANENT)) {
-            return NULL;
+            break;
         }
 
         /* proto bootstrap bit from JS_InitClass omitted. */
         nameString = JS_NewStringCopyZ(cx, exceptions[i].name);
         if (!nameString)
-            return NULL;
+            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)) {
-            return NULL;
+            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
@@ -893,6 +957,8 @@ 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;
@@ -935,56 +1001,37 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
      */
     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.
-     *
-     * XXXbe hack around JSCLASS_NEW_RESOLVE code in js_LookupProperty that
-     *       checks cx->fp, cx->fp->pc, and js_CodeSpec[*cx->fp->pc] in order
-     *       to compute resolve flags such as JSRESOLVE_ASSIGNING.  The bug
-     *       is that this "internal" js_GetClassPrototype call may trigger a
-     *       resolve of exceptions[exn].name if the global object uses a lazy
-     *       standard class resolver (see JS_ResolveStandardClass), but the
-     *       current frame and bytecode end up affecting the resolve flags.
      */
-    {
-        JSStackFrame *fp = cx->fp;
-        jsbytecode *pc = NULL;
-
-        if (fp) {
-            pc = fp->pc;
-            fp->pc = NULL;
-        }
-        ok = js_GetClassPrototype(cx, exceptions[exn].name, &errProto);
-        if (pc)
-            fp->pc = pc;
-        if (!ok)
-            goto out;
-    }
+    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;
     }
-
-    /*
-     * Set the generated Exception object early, so it won't be GC'd by a last
-     * ditch attempt to collect garbage, or a GC that otherwise nests or races
-     * under any of the following calls.  If one of the following calls fails,
-     * it will overwrite this exception object with one of its own (except in
-     * case of OOM errors, of course).
-     */
-    JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
+    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);
@@ -992,6 +1039,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
             ok = JS_FALSE;
             goto out;
         }
+        tv[3] = STRING_TO_JSVAL(filenameStr);
         lineno = reportp->lineno;
     } else {
         filenameStr = cx->runtime->emptyString;
@@ -1014,10 +1062,13 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
     }
     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;
 }
@@ -1028,11 +1079,13 @@ out:
 JSBool
 js_ReportUncaughtException(JSContext *cx)
 {
+    jsval exn, *vp;
     JSObject *exnObject;
+    void *mark;
+    JSErrorReport *reportp, report;
     JSString *str;
-    jsval exn;
-    JSErrorReport *reportp;
     const char *bytes;
+    JSBool ok;
 
     if (!JS_IsExceptionPending(cx))
         return JS_TRUE;
@@ -1042,14 +1095,24 @@ js_ReportUncaughtException(JSContext *cx)
 
     /*
      * Because js_ValueToString below could error and an exception object
-     * could become unrooted, we must root exnObject.
+     * 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);
-        if (!js_AddRoot(cx, &exnObject, "exn.report.root"))
-            return JS_FALSE;
+        vp = js_AllocStack(cx, 5, &mark);
+        if (!vp) {
+            ok = JS_FALSE;
+            goto out;
+        }
+        vp[0] = exn;
     }
 
 #if JS_HAS_ERROR_EXCEPTIONS
@@ -1058,15 +1121,53 @@ js_ReportUncaughtException(JSContext *cx)
     reportp = NULL;
 #endif
 
+    /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
     str = js_ValueToString(cx, exn);
-    bytes = str ? js_GetStringBytes(str) : "null";
+    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 == NULL) {
-        /*
-         * XXXmccabe todo: Instead of doing this, synthesize an error report
-         * struct that includes the filename, lineno where the exception was
-         * originally thrown.
-         */
+    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 {
@@ -1075,10 +1176,11 @@ js_ReportUncaughtException(JSContext *cx)
         js_ReportErrorAgain(cx, bytes, reportp);
     }
 
-    if (exnObject != NULL)
-        js_RemoveRoot(cx->runtime, &exnObject);
     JS_ClearPendingException(cx);
-    return JS_TRUE;
+out:
+    if (exnObject)
+        js_FreeStack(cx, mark);
+    return ok;
 }
 
 #endif /* JS_HAS_EXCEPTIONS */
index ef5e93b29a27ef86d5ced5dd5b22fd92dab648cc..2237dbd4710bc5c64a4e51f904ea58f0cc9dc1e5 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
 #include "jsstddef.h"
 
 /* ----------------- Platform-specific includes and defines ----------------- */
-#ifdef XP_MAC
-#   define FILESEPARATOR         ':'
-#   define FILESEPARATOR2        '\0'
-#   define CURRENT_DIR          "HARD DISK:Desktop Folder"
-/*  TODO: #include <???> */
-#elif defined(XP_WIN) || defined(XP_OS2)
+#if defined(XP_WIN) || defined(XP_OS2)
 #   include <direct.h>
 #   include <io.h>
 #   include <sys/types.h>
 #define STDOUTPUT_NAME          "Standard output stream"
 #define STDERROR_NAME           "Standard error stream"
 
-#define RESOLVE_PATH            js_canonicalPath       /* js_absolutePath */
+#define RESOLVE_PATH            js_canonicalPath        /* js_absolutePath */
 
 /* Error handling */
 typedef enum JSFileErrNum {
@@ -135,10 +131,10 @@ typedef enum JSFileErrNum {
 JSErrorFormatString JSFile_ErrorFormatString[JSFileErr_Limit] = {
 #if JSFILE_HAS_DFLT_MSG_STRINGS
 #define MSG_DEF(name, number, count, exception, format) \
-    { format, count } ,
+    { format, count },
 #else
 #define MSG_DEF(name, number, count, exception, format) \
-    { NULL, count } ,
+    { NULL, count },
 #endif
 #include "jsfile.msg"
 #undef MSG_DEF
@@ -150,65 +146,64 @@ JSFile_GetErrorMessage(void *userRef, const char *locale,
 {
     if ((errorNumber > 0) && (errorNumber < JSFileErr_Limit))
         return &JSFile_ErrorFormatString[errorNumber];
-       else
-           return NULL;
+    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_NATIVE(op)                                               \
+    if (file->isNative) {                                                     \
+        JS_ReportWarning(cx, "Cannot call or access \"%s\" on native file %s",\
+                         op, file->path);                                     \
+        goto out;                                                             \
     }
 
-#define JSFILE_CHECK_WRITE      \
-    if (!file->isOpen){     \
-        JS_ReportWarning(cx,    \
-                "File %s is closed, will open it for writing, proceeding",  \
-                file->path);    \
-        js_FileOpen(cx, obj, file, "write,append,create");     \
-    }else   \
-    if(!js_canWrite(cx, file)){     \
-        JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,  \
-            JSFILEMSG_CANNOT_WRITE, file->path);    \
-        goto out;   \
+#define JSFILE_CHECK_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");     \
-    }else   \
-    if(!js_canRead(cx, file)){     \
-        JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,  \
-            JSFILEMSG_CANNOT_READ, 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_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_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;   \
+#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;                                                             \
     }
 
 
@@ -216,6 +211,8 @@ JSFile_GetErrorMessage(void *userRef, const char *locale,
     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... */
@@ -225,14 +222,13 @@ JSFile_GetErrorMessage(void *userRef, const char *locale,
 typedef struct JSFile {
     char        *path;          /* the path to the file. */
     JSBool      isOpen;
-    JSString    *linebuffer;    /* temp buffer used by readln. */
     int32       mode;           /* mode used to open the file: read, write, append, create, etc.. */
     int32       type;           /* Asciiz, utf, unicode */
     char        byteBuffer[3];  /* bytes read in advance by js_FileRead ( UTF8 encoding ) */
     jsint       nbBytesInBuf;   /* number of bytes stored in the buffer above */
     jschar      charBuffer;     /* character read in advance by readln ( mac files only ) */
     JSBool      charBufferUsed; /* flag indicating if the buffer above is being used */
-    JSBool      hasRandomAccess;   /* can the file be randomly accessed? false for stdin, and
+    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 */
@@ -248,26 +244,23 @@ 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 -------------------------- */
+/* New filename manipulation procesures */
 /* assumes we don't have leading/trailing spaces */
 static JSBool
 js_filenameHasAPipe(const char *filename)
 {
-#ifdef XP_MAC
-    /* pipes are not supported on the MAC */
-    return JS_FALSE;
-#else
-    if(!filename) return JS_FALSE;
-    return  filename[0]==PIPE_SYMBOL ||
-            filename[strlen(filename)-1]==PIPE_SYMBOL;
-#endif
+    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 (strlen(name)>1)?((name[1]==':')?JS_TRUE:JS_FALSE):JS_FALSE;
+    return *name && name[1] == ':';
 #else
     return (name[0]
 #   if defined(XP_UNIX) || defined(XP_BEOS)
@@ -275,31 +268,28 @@ js_isAbsolute(const char *name)
 #   else
             !=
 #   endif
-            FILESEPARATOR)?JS_TRUE:JS_FALSE;
+            FILESEPARATOR);
 #endif
 }
 
 /*
   Concatinates base and name to produce a valid filename.
   Returned string must be freed.
* Concatinates base and name to produce a valid filename.
* Returned string must be freed.
 */
 static char*
 js_combinePath(JSContext *cx, const char *base, const char *name)
 {
     int len = strlen(base);
-    char* result = (char*)JS_malloc(cx, len+strlen(name)+2);
+    char* result = JS_malloc(cx, len + strlen(name) + 2);
 
-    if (!result)  return NULL;
+    if (!result)
+        return NULL;
 
     strcpy(result, base);
 
-    if (base[len-1]!=FILESEPARATOR
-#if defined(XP_WIN) || defined(XP_OS2)
-            && base[len-1]!=FILESEPARATOR2
-#endif
-            ) {
-      result[len] = FILESEPARATOR;
-      result[len+1] = '\0';
+    if (base[len - 1] != FILESEPARATOR && base[len - 1] != FILESEPARATOR2) {
+        result[len] = FILESEPARATOR;
+        result[len + 1] = '\0';
     }
     strcat(result, name);
     return result;
@@ -312,85 +302,96 @@ js_fileBaseName(JSContext *cx, const char *pathname)
     jsint index, aux;
     char *result;
 
-#if defined(XP_WIN) || defined(XP_OS2)
-    /* First, get rid of the drive selector */
-    if ((strlen(pathname)>=2)&&(pathname[1]==':')) {
-        pathname = &pathname[2];
-    }
-#endif
     index = strlen(pathname)-1;
-    /*
-        remove trailing separators -- don't necessarily need to check for
-        FILESEPARATOR2, but that's fine
-    */
-    while ((index>0)&&((pathname[index]==FILESEPARATOR)||
-                       (pathname[index]==FILESEPARATOR2))) index--;
+
+    /* 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 = (char*)JS_malloc(cx, aux-index+1);
-    if (!result)  return NULL;
-    strncpy(result, &pathname[index+1], aux-index);
-    result[aux-index] = '\0';
+
+    /* 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 everytynig but the last component from a path name.
   Returned string must be freed. Returned string must be freed.
-*/
* Returns everything but the last component from a path name.
* Returned string must be freed.
+ */
 static char *
 js_fileDirectoryName(JSContext *cx, const char *pathname)
 {
-    jsint index;
-    char  *result;
+    char *result;
+    const char *cp, *end;
+    size_t pathsize;
 
-#if defined(XP_WIN) || defined(XP_OS2)
-    char  drive = '\0';
-    const char *oldpathname = pathname;
+    end = pathname + strlen(pathname);
+    cp = end - 1;
 
-    /* First, get rid of the drive selector */
-    if ((strlen(pathname)>=2)&&(pathname[1]==':')) {
-        drive = pathname[0];
-        pathname = &pathname[2];
+    /* If this is already a directory, chop off the trailing /s. */
+    while (cp >= pathname) {
+        if (*cp != FILESEPARATOR && *cp != FILESEPARATOR2)
+            break;
+        --cp;
     }
-#endif
-    index = strlen(pathname)-1;
-    while ((index>0)&&((pathname[index]==FILESEPARATOR)||
-                       (pathname[index]==FILESEPARATOR2))) index--;
-    while ((index>0)&&(pathname[index]!=FILESEPARATOR)&&
-                      (pathname[index]!=FILESEPARATOR2)) index--;
-
-    if (index>=0){
-        result = (char*)JS_malloc(cx, index+4);
-        if (!result)  return NULL;
-#if defined(XP_WIN) || defined(XP_OS2)
-        if (drive!='\0') {
-            result[0] = toupper(drive);
-            result[1] = ':';
-            strncpy(&result[2], pathname, index);
-                       result[index+3] = '\0';
-        }else
-#endif
-        {
-            strncpy(result, pathname, index);
-                       result[index] = '\0';
+
+    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);
         }
 
-        /* add terminating separator */
-        index = strlen(result)-1;
-        result[index] = FILESEPARATOR;
-        result[index+1] = '\0';
-    } else{
-#if defined(XP_WIN) || defined(XP_OS2)
-        result = JS_strdup(cx, oldpathname); /* may include drive selector */
-#else
-        result = JS_strdup(cx, pathname);
-#endif
+        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;
 }
 
@@ -401,25 +402,27 @@ js_absolutePath(JSContext *cx, const char * path)
     JSString *str;
     jsval prop;
 
-    if (js_isAbsolute(path)){
+    if (js_isAbsolute(path)) {
         return JS_strdup(cx, path);
-    }else{
+    } else {
         obj = JS_GetGlobalObject(cx);
         if (!JS_GetProperty(cx, obj, FILE_CONSTRUCTOR, &prop)) {
             JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-                 JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR);
+                                 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);
+                                 JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR);
             return JS_strdup(cx, path);
         }
+
         str = JS_ValueToString(cx, prop);
-        if (!str ) {
+        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);
     }
@@ -438,26 +441,37 @@ js_canonicalPath(JSContext *cx, char *oldpath)
 
     /* This is probably optional */
        /* Remove possible spaces in the beginning and end */
-    while(i<strlen(path)-1 && path[i]==' ') i++;
-       while(j>=0 && path[j]==' ') j--;
+    while (i < j && path[i] == ' ')
+        i++;
+    while (j >= 0 && path[j] == ' ')
+        j--;
 
-       tmp = JS_malloc(cx, j-i+2);
-       strncpy(tmp, &path[i], j-i+1);
-    tmp[j-i+1] = '\0';
+    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 JS_strdup(cx, path);
-    /* file:// support */
-    if(!strncmp(path, URL_PREFIX, strlen(URL_PREFIX)))
-        return js_canonicalPath(cx, &path[strlen(URL_PREFIX)-1]);
+    /* Pipe support. */
+    if (js_filenameHasAPipe(path))
+        return path;
 
-    if (!js_isAbsolute(path))
-        path = js_absolutePath(cx, path);
-    else
-        path = JS_strdup(cx, 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, "");
 
@@ -466,30 +480,23 @@ js_canonicalPath(JSContext *cx, char *oldpath)
     base = js_fileBaseName(cx, current);
     dir = js_fileDirectoryName(cx, current);
 
-    /* TODO: MAC -- not going to work??? */
     while (strcmp(dir, current)) {
         if (!strcmp(base, "..")) {
             back++;
-        } else
-        if(!strcmp(base, ".")){
-            /* ??? */
         } else {
-            if (back>0)
+            if (back > 0) {
                 back--;
-            else {
+            else {
                 tmp = result;
-                result = JS_malloc(cx, strlen(base)+1+strlen(tmp)+1);
-                if (!result) {
-                    JS_free(cx, dir);
-                    JS_free(cx, base);
-                    JS_free(cx, current);
-                    return NULL;
-                }
+                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';
+                    result[c + 1] = '\0';
                     strcat(result, tmp);
                 }
                 JS_free(cx, tmp);
@@ -504,12 +511,9 @@ js_canonicalPath(JSContext *cx, char *oldpath)
 
     tmp = result;
     result = JS_malloc(cx, strlen(dir)+1+strlen(tmp)+1);
-    if (!result) {
-        JS_free(cx, dir);
-        JS_free(cx, base);
-        JS_free(cx, current);
-        return NULL;
-    }
+    if (!result)
+        goto out;
+
     strcpy(result, dir);
     c = strlen(result);
     if (tmp[0]!='\0') {
@@ -519,10 +523,16 @@ js_canonicalPath(JSContext *cx, char *oldpath)
         }
         strcat(result, tmp);
     }
-    JS_free(cx, tmp);
-    JS_free(cx, dir);
-    JS_free(cx, base);
-    JS_free(cx, current);
+
+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;
 }
@@ -581,46 +591,47 @@ js_canonicalPath(JSContext *cx, char *oldpath)
 #define LINE_SEPARATOR      0x2028
 #define PARAGRAPH_SEPARATOR 0x2029
 static int16 one_ucs2_to_utf8_char(unsigned char *tobufp,
-        unsigned char *tobufendp, uint16 onechar)
+                                   unsigned char *tobufendp,
+                                   uint16 onechar)
 {
+    int16 numUTF8bytes = 0;
 
-     int16 numUTF8bytes = 0;
-
-    if((onechar == LINE_SEPARATOR)||(onechar == PARAGRAPH_SEPARATOR))
-    {
+    if (onechar == LINE_SEPARATOR || onechar == PARAGRAPH_SEPARATOR) {
         strcpy((char*)tobufp, "\n");
-        return strlen((char*)tobufp);;
+        return strlen((char*)tobufp);
     }
 
-        if (onechar < 0x80) {               numUTF8bytes = 1;
-        } else if (onechar < 0x800) {       numUTF8bytes = 2;
-        } else if (onechar <= MAX_UCS2) {   numUTF8bytes = 3;
-        } else { numUTF8bytes = 2;
-                 onechar = DEFAULT_CHAR;
-        }
+    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);
-        }
+    tobufp += numUTF8bytes;
 
+    /* return error if we don't have space for the whole character */
+    if (tobufp > tobufendp) {
+        return(-1);
+    }
 
-        switch(numUTF8bytes) {
+    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 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 2: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6;
-                    *--tobufp = onechar | TWO_OCTET_BASE;
-                    break;
-            case 1: *--tobufp = (unsigned char)onechar;  break;
-        }
+      case 1: *--tobufp = (unsigned char)onechar;
+              break;
+    }
 
-        return(numUTF8bytes);
+    return numUTF8bytes;
 }
 
 /*
@@ -707,7 +718,7 @@ js_FileHasOption(JSContext *cx, const char *oldoptions, const char *name)
     char *options = JS_strdup(cx, oldoptions);
     int32 found = 0;
 
-       current = options;
+    current = options;
     for (;;) {
         comma = strchr(current, ',');
         if (comma) *comma = '\0';
@@ -735,22 +746,22 @@ js_ResetBuffers(JSFile * file)
 {
     file->charBufferUsed = JS_FALSE;
     file->nbBytesInBuf = 0;
-    file->linebuffer = NULL;    /* TODO: check for mem. leak? */
 }
 
 /* Reset file attributes */
 static void
-js_ResetAttributes(JSFile * file){
-       file->mode = file->type = 0;
+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->hasRandomAccess = JS_TRUE; /* Innocent until proven guilty. */
+    file->hasAutoflush = JS_FALSE;
     file->isNative = JS_FALSE;
     file->isPipe = JS_FALSE;
 
-       js_ResetBuffers(file);
+    js_ResetBuffers(file);
 }
 
 static JSBool
@@ -764,9 +775,8 @@ js_FileOpen(JSContext *cx, JSObject *obj, JSFile *file, char *mode){
     v[0] = STRING_TO_JSVAL(mask);
     v[1] = STRING_TO_JSVAL(type);
 
-    if (!file_open(cx, obj, 2, v, &rval)) {
+    if (!file_open(cx, obj, 2, v, &rval))
         return JS_FALSE;
-    }
     return JS_TRUE;
 }
 
@@ -787,18 +797,18 @@ js_BufferedRead(JSFile * f, char *buf, int32 len)
     }
 
     if (len>0) {
-        count+= (!f->isNative)?
-                    PR_Read(f->handle, buf, len):
-                    fread(buf, 1, len, f->nativehandle);
+        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)
+js_FileRead(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode)
 {
-    unsigned char*aux;
-    int32 count, i;
+    unsigned char *aux;
+    int32 count = 0, i;
     jsint remainder;
     unsigned char utfbuf[3];
 
@@ -810,22 +820,24 @@ js_FileRead(JSContext *cx, JSFile * file, jschar*buf, int32 len, int32 mode)
     }
 
     switch (mode) {
-    case ASCII:
+      case ASCII:
         aux = (unsigned char*)JS_malloc(cx, len);
-        if (!aux) {
-        return 0;
-        }
+        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];
+        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:
+
+      case UTF8:
         remainder = 0;
         for (count = 0;count<len;count++) {
             i = js_BufferedRead(file, utfbuf+remainder, 3-remainder);
@@ -840,13 +852,12 @@ js_FileRead(JSContext *cx, JSFile * file, jschar*buf, int32 len, int32 mode)
                     utfbuf[0] = utfbuf[1];
                     utfbuf[1] = utfbuf[2];
                     remainder = 2;
-                } else
-                if (i==2) {
+                } else if (i==2) {
                     utfbuf[0] = utfbuf[2];
                     remainder = 1;
-                } else
-                if (i==3)
+                } else if (i==3) {
                     remainder = 0;
+                }
             }
         }
         while (remainder>0) {
@@ -857,17 +868,22 @@ js_FileRead(JSContext *cx, JSFile * file, jschar*buf, int32 len, int32 mode)
             remainder--;
         }
         break;
-    case UCS2:
-        count = js_BufferedRead(file, (char*)buf, len*2)>>1;
-        if (count==-1) {
+
+      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){
+    if(count == -1) {
         JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-            JSFILEMSG_OP_FAILED, "read", file->path);
+                             JSFILEMSG_OP_FAILED, "read", file->path);
     }
 
     return count;
@@ -876,16 +892,17 @@ js_FileRead(JSContext *cx, JSFile * file, jschar*buf, int32 len, int32 mode)
 static int32
 js_FileSeek(JSContext *cx, JSFile *file, int32 len, int32 mode)
 {
-    int32 count, i;
+    int32 count = 0, i;
     jsint remainder;
     unsigned char utfbuf[3];
     jschar tmp;
 
     switch (mode) {
-    case ASCII:
+      case ASCII:
         count = PR_Seek(file->handle, len, PR_SEEK_CUR);
         break;
-    case UTF8:
+
+      case UTF8:
         remainder = 0;
         for (count = 0;count<len;count++) {
             i = js_BufferedRead(file, utfbuf+remainder, 3-remainder);
@@ -896,18 +913,16 @@ js_FileSeek(JSContext *cx, JSFile *file, int32 len, int32 mode)
             if (i<0) {
                 return 0;
             } else {
-
                 if (i==1) {
                     utfbuf[0] = utfbuf[1];
                     utfbuf[1] = utfbuf[2];
                     remainder = 2;
-                } else
-                if (i==2) {
+                } else if (i==2) {
                     utfbuf[0] = utfbuf[2];
                     remainder = 1;
-                } else
-                if (i==3)
+                } else if (i==3) {
                     remainder = 0;
+                }
             }
         }
         while (remainder>0) {
@@ -917,15 +932,20 @@ js_FileSeek(JSContext *cx, JSFile *file, int32 len, int32 mode)
             utfbuf[1] = utfbuf[2];
             remainder--;
         }
-      break;
-    case UCS2:
+        break;
+
+      case UCS2:
         count = PR_Seek(file->handle, len*2, PR_SEEK_CUR)/2;
         break;
+
+      default:
+        /* Not reached. */
+        JS_ASSERT(0);
     }
 
-    if(count==-1){
+    if(count == -1) {
         JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-            JSFILEMSG_OP_FAILED, "seek", file->path);
+                             JSFILEMSG_OP_FAILED, "seek", file->path);
     }
 
     return count;
@@ -935,29 +955,31 @@ static int32
 js_FileWrite(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode)
 {
     unsigned char   *aux;
-    int32           count, i, j;
+    int32           count = 0, i, j;
     unsigned char   *utfbuf;
 
     switch (mode) {
-    case ASCII:
+      case ASCII:
         aux = (unsigned char*)JS_malloc(cx, len);
-        if (!aux)  return 0;
+        if (!aux)
+            return 0;
 
-        for (i = 0; i<len; i++) {
-            aux[i]=buf[i]%256;
-        }
+        for (i = 0; i<len; i++)
+            aux[i] = buf[i] % 256;
 
-        count = (!file->isNative)?
-                    PR_Write(file->handle, aux, len):
-                    fwrite(aux, 1, len, file->nativehandle);
+        count = (!file->isNative)
+                ? PR_Write(file->handle, aux, len)
+                : fwrite(aux, 1, len, file->nativehandle);
 
         if (count==-1) {
             JS_free(cx, aux);
             return 0;
         }
+
         JS_free(cx, aux);
         break;
-    case UTF8:
+
+      case UTF8:
         utfbuf = (unsigned char*)JS_malloc(cx, len*3);
         if (!utfbuf)  return 0;
         i = 0;
@@ -969,30 +991,36 @@ js_FileWrite(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode)
             }
             i+=j;
         }
-        j = (!file->isNative)?
-                PR_Write(file->handle, utfbuf, i):
-                fwrite(utfbuf, 1, i, file->nativehandle);
+        j = (!file->isNative) 
+            ? PR_Write(file->handle, utfbuf, i)
+            : fwrite(utfbuf, 1, i, file->nativehandle);
 
         if (j<i) {
             JS_free(cx, utfbuf);
             return 0;
         }
         JS_free(cx, utfbuf);
-      break;
-    case UCS2:
-        count = (!file->isNative)?
-                PR_Write(file->handle, buf, len*2)>>1:
-                fwrite(buf, 1, len*2, file->nativehandle)>>1;
+        break;
 
-        if (count==-1) {
+      case UCS2:
+        count = (!file->isNative) 
+                ? PR_Write(file->handle, buf, len*2) >> 1
+                : fwrite(buf, 1, len*2, file->nativehandle) >> 1;
+
+        if (count == -1)
             return 0;
-        }
         break;
+
+      default:
+        /* Not reached. */
+        JS_ASSERT(0);
     }
-    if(count==-1){
+
+    if(count == -1) {
         JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-            JSFILEMSG_OP_FAILED, "write", file->path);
+                             JSFILEMSG_OP_FAILED, "write", file->path);
     }
+
     return count;
 }
 
@@ -1000,65 +1028,68 @@ js_FileWrite(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode)
 static JSBool
 js_exists(JSContext *cx, JSFile *file)
 {
-    if(!file->isNative){
-        return (PR_Access(file->path, PR_ACCESS_EXISTS)==PR_SUCCESS);
-    }else{
-        /* doesn't make sense for a pipe of stdstream */
+    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);
-    }else{
-        if(file->isPipe){
-            /* pipe open for reading */
-            return file->path[0]==PIPE_SYMBOL;
-        }else{
-            return !strcmp(file->path, STDINPUT_NAME);
-        }
+    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);
-    }else{
-        if(file->isPipe){
-            /* pipe open for writing */
-            return file->path[strlen(file->path)-1]==PIPE_SYMBOL;
-        }else{
-            return  !strcmp(file->path, STDOUTPUT_NAME) ||
-                    !strcmp(file->path, STDERROR_NAME);
-        }
+    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){
+    if (!file->isNative) {
         PRFileInfo info;
 
-        if ((file->isOpen)?
-                        PR_GetOpenFileInfo(file->handle, &info):
-                        PR_GetFileInfo(file->path, &info)!=PR_SUCCESS){
+        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);
+                                 JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
             return JS_FALSE;
-        }else
-            return (info.type==PR_FILE_FILE);
-    }else{
-        /* doesn't make sense for a pipe of stdstream */
-        return JS_FALSE;
+        }
+
+        return info.type == PR_FILE_FILE;
     }
+
+    /* This doesn't make sense for a pipe of stdstream. */
+    return JS_FALSE;
 }
 
 static JSBool
@@ -1067,21 +1098,23 @@ 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;
+        /* 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){
+        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);
+                                 JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
             return JS_FALSE;
-        }else
-            return (info.type==PR_FILE_DIRECTORY);
-    }else{
-        /* doesn't make sense for a pipe of stdstream */
-        return JS_FALSE;
+        }
+
+        return info.type == PR_FILE_DIRECTORY;
     }
+
+    /* This doesn't make sense for a pipe of stdstream. */
+    return JS_FALSE;
 }
 
 static jsval
@@ -1091,44 +1124,77 @@ js_size(JSContext *cx, JSFile *file)
 
     JSFILE_CHECK_NATIVE("size");
 
-    if ((file->isOpen)?
-                    PR_GetOpenFileInfo(file->handle, &info):
-                    PR_GetFileInfo(file->path, &info)!=PR_SUCCESS){
+    if (file->isOpen
+        ? PR_GetOpenFileInfo(file->handle, &info)
+        : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) {
         JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-            JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
-        goto out;
-    }else
-        return INT_TO_JSVAL(info.size);
+                             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 jsval
-js_parent(JSContext *cx, JSFile *file)
+/*
+ * 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)  return JSVAL_VOID;
+    /* 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);
-    /* root.parent = null ??? */
-    if(!strcmp(file->path, str) ||
-            (!strncmp(str, file->path, strlen(str)-1)&&
-            file->path[strlen(file->path)]-1)==FILESEPARATOR){
-        return JSVAL_NULL;
-    }else{
-        return OBJECT_TO_JSVAL(js_NewFileObject(cx, str));
-        JS_free(cx, str);
+    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 jsval
-js_name(JSContext *cx, JSFile *file){
-    return  file->isPipe?
-                JSVAL_VOID:
-                STRING_TO_JSVAL(JS_NewStringCopyZ(cx, js_fileBaseName(cx, file->path)));
+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 ---------------------------- */
@@ -1141,26 +1207,28 @@ file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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){
+    if(file->isOpen && file->isNative) {
         JS_ReportWarning(cx, "Native file %s is already open, proceeding",
-            file->path);
+                         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;
+        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)){
+    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);
+                         "trying to open it, proceeding", file->path);
         goto good;
     }
 
@@ -1168,23 +1236,23 @@ file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     len = strlen(file->path);
 
     /* Mode */
-    if (argc>=1){
+    if (argc >= 1) {
         strmode = JS_ValueToString(cx, argv[0]);
-        if (!strmode){
+        if (!strmode) {
             JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-                JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR, argv[0]);
+                                 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){
+    } else {
+        if(file->path[0]==PIPE_SYMBOL) {
             /* pipe default mode */
             mode = JS_strdup(cx, "read");
-        }else
-        if(file->path[len-1]==PIPE_SYMBOL){
+        } else if(file->path[len-1]==PIPE_SYMBOL) {
             /* pipe default mode */
             mode = JS_strdup(cx, "write");
-        }else{
+        } else {
             /* non-destructive, permissive defaults. */
             mode = JS_strdup(cx, "readWrite,append,create");
         }
@@ -1192,42 +1260,44 @@ file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
     /* Process the mode */
     mask = 0;
-    /* TODO: this is pretty ugly, BTW, we walk thru the string too many times */
-    mask|=(js_FileHasOption(cx, mode, "read"))?      PR_RDONLY       :   0;
-    mask|=(js_FileHasOption(cx, mode, "write"))?     PR_WRONLY       :   0;
-    mask|=(js_FileHasOption(cx, mode, "readWrite"))? PR_RDWR         :   0;
-    mask|=(js_FileHasOption(cx, mode, "append"))?    PR_APPEND       :   0;
-    mask|=(js_FileHasOption(cx, mode, "create"))?    PR_CREATE_FILE  :   0;
-    mask|=(js_FileHasOption(cx, mode, "replace"))?   PR_TRUNCATE     :   0;
+    /* 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;
+    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"));
+    file->hasAutoflush |= js_FileHasOption(cx, mode, "autoflush");
 
     /* Type */
-    if (argc>1) {
+    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]);
+                                JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR,
+                                 argv[1]);
             goto out;
         }
         ctype = JS_GetStringBytes(strtype);
 
-        if(!strcmp(ctype, utfstring))
+        if(!strcmp(ctype, utfstring)) {
             type = UTF8;
-        else
-        if (!strcmp(ctype, unicodestring))
+        } else if (!strcmp(ctype, unicodestring)) {
             type = UCS2;
-        else{
-            if(strcmp(ctype, asciistring)){
+        } else {
+            if (strcmp(ctype, asciistring)) {
                 JS_ReportWarning(cx, "File type %s is not supported, using "
-                        "'text' instead, proceeding", ctype);
+                                 "'text' instead, proceeding", ctype);
             }
             type = ASCII;
         }
-    }else{
+    } else {
         type = ASCII;
     }
 
@@ -1235,52 +1305,56 @@ file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     file->type = type;
     file->mode = mask;
     file->nativehandle = NULL;
-    file->hasRandomAccess = (type!=UTF8);
+    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){
+     * 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{
+                                 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);
+                                   JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES,
+                                         mode, file->path);
                     goto out;
                 }
                 /* open(SPOOLER, "| cat -v | lpr -h 2>/dev/null") -- pipe for writing */
-                pipemode[0] = 'r';
-                pipemode[1] = file->type==UTF8?'b':'t';
-                pipemode[2] = '\0';
+                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){
+            } else if(file->path[len-1] == PIPE_SYMBOL) {
                 char *command = JS_malloc(cx, len);
 
                 strncpy(command, file->path, len-1);
                 command[len-1] = '\0';
                 /* open(STATUS, "netstat -an 2>&1 |") */
-                pipemode[0] = 'w';
-                pipemode[1] = file->type==UTF8?'b':'t';
-                pipemode[2] = '\0';
+                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);
+                JS_free(cx, command);
             }
             /* set the flags */
             file->isNative = JS_TRUE;
             file->isPipe  = JS_TRUE;
             file->hasRandomAccess = JS_FALSE;
         }
-    }else{
+    } else {
         /* TODO: what about the permissions?? Java ignores the problem... */
         file->handle = PR_Open(file->path, mask, 0644);
     }
@@ -1290,21 +1364,22 @@ file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     mode = NULL;
 
     /* Set the open flag and return result */
-    if (file->handle==NULL && file->nativehandle==NULL){
-               file->isOpen = JS_FALSE;
+    if (file->handle == NULL && file->nativehandle == NULL) {
+        file->isOpen = JS_FALSE;
 
         JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-            JSFILEMSG_OP_FAILED, "open", file->path);
+                             JSFILEMSG_OP_FAILED, "open", file->path);
         goto out;
-    }else
-        goto good;
+    }
+
 good:
     file->isOpen = JS_TRUE;
     *rval = JSVAL_TRUE;
     return JS_TRUE;
+
 out:
-    if(mode) JS_free(cx, mode);
-    *rval = JSVAL_VOID;
+    if(mode)
+        JS_free(cx, mode);
     return JS_FALSE;
 }
 
@@ -1344,8 +1419,8 @@ file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     js_ResetAttributes(file);
     *rval = JSVAL_TRUE;
     return JS_TRUE;
+
 out:
-    *rval = JSVAL_FALSE;
     return JS_FALSE;
 }
 
@@ -1660,71 +1735,83 @@ file_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     JSFile      *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
     JSString    *str;
-    jschar      *buf;
-    int32       offset;
+    jschar      *buf = NULL, *tmp;
+    int32       offset, read;
     intN        room;
     jschar      data, data2;
-    JSBool      endofline;
 
     SECURITY_CHECK(cx, NULL, "readln", file);
     JSFILE_CHECK_READ;
 
-    if (!file->linebuffer) {
-        buf = JS_malloc(cx, MAX_LINE_LENGTH*(sizeof data));
-        if (!buf) goto out;
-        file->linebuffer = JS_NewUCString(cx, buf, MAX_LINE_LENGTH);
-    }
-    room = JS_GetStringLength(file->linebuffer);
+    buf = JS_malloc(cx, MAX_LINE_LENGTH * sizeof data);
+    if (!buf)
+        return JS_FALSE;
+
+    room = MAX_LINE_LENGTH - 1;
     offset = 0;
 
-    /* XXX TEST ME!! TODO: yes, please do */
-    for(;;) {
-        if (!js_FileRead(cx, file, &data, 1, file->type)) {
-            endofline = JS_FALSE;
-            goto loop;
-        }
+    for (;;) {
+        read = js_FileRead(cx, file, &data, 1, file->type);
+        if (read < 0)
+            goto out;
+        if (read == 0)
+            goto eof;
+
         switch (data) {
-        case '\n' :
-            endofline = JS_TRUE;
-            goto loop;
-        case '\r' :
-            if (!js_FileRead(cx, file, &data2, 1, file->type)) {
-                endofline = JS_TRUE;
-                goto loop;
-            }
-            if (data2!='\n') { /* We read one char too far.  Buffer it. */
+          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;
             }
-            endofline = JS_TRUE;
-            goto loop;
-        default:
+
+            /* Fall through. */
+          case '\n':
+            goto done;
+
+          default:
             if (--room < 0) {
-                buf = JS_malloc(cx, (offset+MAX_LINE_LENGTH)*sizeof data);
-                if (!buf) return JS_FALSE;
-                room = MAX_LINE_LENGTH-1;
-                memcpy(buf, JS_GetStringChars(file->linebuffer),
-                    JS_GetStringLength(file->linebuffer));
-                /* what follows may not be the cleanest way. */
-                file->linebuffer->chars = buf;
-                file->linebuffer->length =  offset+MAX_LINE_LENGTH;
+                tmp = JS_realloc(cx, buf,
+                                 (offset + MAX_LINE_LENGTH) * sizeof data);
+                if (!tmp)
+                    goto out;
+
+                room = MAX_LINE_LENGTH - 1;
+                buf = tmp;
             }
-            file->linebuffer->chars[offset++] = data;
+
+            buf[offset++] = data;
             break;
         }
     }
-loop:
-    file->linebuffer->chars[offset] = 0;
-    if ((endofline==JS_TRUE)) {
-        str = JS_NewUCStringCopyN(cx, JS_GetStringChars(file->linebuffer),
-                                    offset);
-        *rval = STRING_TO_JSVAL(str);
+
+eof:
+    if (offset == 0) {
+        *rval = JSVAL_NULL;
         return JS_TRUE;
-    }else{
-        goto out;
     }
+
+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:
-    *rval = JSVAL_NULL;
+    if (buf)
+        JS_free(cx, buf);
+
     return JS_FALSE;
 }
 
@@ -1735,23 +1822,26 @@ file_readAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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;
 
-    while(file_readln(cx, obj, 0, NULL, &line)){
-        JS_SetElement(cx, array, len, &line);
-        len++;
+    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);
     }
 
-    *rval = OBJECT_TO_JSVAL(array);
-    return JS_TRUE;
 out:
-    *rval = JSVAL_FALSE;
-    return JS_FALSE;
+    return lineok;
 }
 
 static JSBool
@@ -1976,18 +2066,18 @@ 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){
+    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);
+        if (file->path)
+            JS_free(cx, file->path);
 
-               JS_free(cx, file);
-       }
+        JS_free(cx, file);
+    }
 }
 
 /*
@@ -1996,10 +2086,11 @@ file_finalize(JSContext *cx, JSObject *obj)
 static JSFile*
 file_init(JSContext *cx, JSObject *obj, char *bytes)
 {
-    JSFile      *file;
+    JSFile *file;
 
     file = JS_malloc(cx, sizeof *file);
-    if (!file) return NULL;
+    if (!file)
+        return NULL;
     memset(file, 0 , sizeof *file);
 
     js_ResetAttributes(file);
@@ -2008,11 +2099,12 @@ file_init(JSContext *cx, JSObject *obj, char *bytes)
 
     if (!JS_SetPrivate(cx, obj, file)) {
         JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-            JSFILEMSG_CANNOT_SET_PRIVATE_FILE, file->path);
+                             JSFILEMSG_CANNOT_SET_PRIVATE_FILE, file->path);
         JS_free(cx, file);
         return NULL;
-    }else
-        return file;
+    }
+
+    return file;
 }
 
 /* Returns a JSObject. This function is globally visible */
@@ -2040,9 +2132,6 @@ js_NewFileObjectFromFILE(JSContext *cx, FILE *nativehandle, char *filename,
 {
     JSObject *obj;
     JSFile   *file;
-#ifdef XP_MAC
-    JS_ReportWarning(cx, "Native files are not fully supported on the MAC");
-#endif
 
     obj = JS_NewObject(cx, &file_class, NULL, NULL);
     if (!obj){
@@ -2073,28 +2162,37 @@ js_NewFileObjectFromFILE(JSContext *cx, FILE *nativehandle, char *filename,
 */
 static JSBool
 file_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-    jsval *rval)
+                 jsval *rval)
 {
     JSString *str;
     JSFile   *file;
 
-    str = (argc==0)?JS_InternString(cx, ""):JS_ValueToString(cx, argv[0]);
+    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){
+    if (!str) {
         JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
-            JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR, argv[0]);
-        goto out;
+                         JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR,
+                             argv[0]);
+        return JS_FALSE;
     }
 
     file = file_init(cx, obj, JS_GetStringBytes(str));
-    if (!file)  goto out;
+    if (!file)
+        return JS_FALSE;
 
     SECURITY_CHECK(cx, NULL, "constructor", file);
 
     return JS_TRUE;
-out:
-    *rval = JSVAL_VOID;
-    return JS_FALSE;
 }
 
 /* -------------------- File methods and properties ------------------------- */
@@ -2114,8 +2212,8 @@ static JSFunctionSpec file_functions[] = {
     { "writeAll",       file_writeAll, 0},
     { "list",           file_list, 0},
     { "mkdir",          file_mkdir, 0},
-       { "toString",       file_toString, 0},
-    { "toURL",                 file_toURL, 0},
+    { "toString",       file_toString, 0},
+    { "toURL",          file_toURL, 0},
     {0}
 };
 
@@ -2173,26 +2271,32 @@ static JSBool
 file_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     JSFile      *file = JS_GetInstancePrivate(cx, obj, &file_class, NULL);
-    char        *str;
+    char        *bytes;
+    JSString    *str;
     jsint       tiny;
     PRFileInfo  info;
-       JSBool          flag;
-    PRExplodedTime
-                expandedTime;
+    JSBool      flag;
+    PRExplodedTime expandedTime;
 
     tiny = JSVAL_TO_INT(id);
-    if(!file) return JS_TRUE;
+    if (!file)
+        return JS_TRUE;
 
     switch (tiny) {
     case FILE_PARENT:
         SECURITY_CHECK(cx, NULL, "parent", file);
-        *vp = js_parent(cx, file);
+        if (!js_parent(cx, file, vp))
+            return JS_FALSE;
         break;
     case FILE_PATH:
-        *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, file->path));
+        str = JS_NewStringCopyZ(cx, file->path);
+        if (!str)
+            return JS_FALSE;
+        *vp = STRING_TO_JSVAL(str);
         break;
     case FILE_NAME:
-        *vp = js_name(cx, file);
+        if (!js_name(cx, file, vp))
+            return JS_FALSE;
         break;
     case FILE_ISDIR:
         SECURITY_CHECK(cx, NULL, "isDirectory", file);
@@ -2265,47 +2369,47 @@ file_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
     case FILE_MODE:
         SECURITY_CHECK(cx, NULL, "mode", file);
         JSFILE_CHECK_OPEN("mode");
-        str = (char*)JS_malloc(cx, MODE_SIZE);
-        str[0] = '\0';
+        bytes = JS_malloc(cx, MODE_SIZE);
+        bytes[0] = '\0';
         flag = JS_FALSE;
 
         if ((file->mode&PR_RDONLY)==PR_RDONLY) {
-            if (flag) strcat(str, ",");
-            strcat(str, "read");
+            if (flag) strcat(bytes, ",");
+            strcat(bytes, "read");
             flag = JS_TRUE;
         }
         if ((file->mode&PR_WRONLY)==PR_WRONLY) {
-            if (flag) strcat(str, ",");
-            strcat(str, "write");
+            if (flag) strcat(bytes, ",");
+            strcat(bytes, "write");
             flag = JS_TRUE;
         }
         if ((file->mode&PR_RDWR)==PR_RDWR) {
-            if (flag) strcat(str, ",");
-            strcat(str, "readWrite");
+            if (flag) strcat(bytes, ",");
+            strcat(bytes, "readWrite");
             flag = JS_TRUE;
         }
         if ((file->mode&PR_APPEND)==PR_APPEND) {
-            if (flag) strcat(str, ",");
-            strcat(str, "append");
+            if (flag) strcat(bytes, ",");
+            strcat(bytes, "append");
             flag = JS_TRUE;
         }
         if ((file->mode&PR_CREATE_FILE)==PR_CREATE_FILE) {
-            if (flag) strcat(str, ",");
-            strcat(str, "create");
+            if (flag) strcat(bytes, ",");
+            strcat(bytes, "create");
             flag = JS_TRUE;
         }
         if ((file->mode&PR_TRUNCATE)==PR_TRUNCATE) {
-            if (flag) strcat(str, ",");
-            strcat(str, "replace");
+            if (flag) strcat(bytes, ",");
+            strcat(bytes, "replace");
             flag = JS_TRUE;
         }
         if (file->hasAutoflush) {
-            if (flag) strcat(str, ",");
-            strcat(str, "hasAutoFlush");
+            if (flag) strcat(bytes, ",");
+            strcat(bytes, "hasAutoFlush");
             flag = JS_TRUE;
         }
-        *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str));
-        JS_free(cx, str);
+        *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, bytes));
+        JS_free(cx, bytes);
         break;
     case FILE_CREATED:
         SECURITY_CHECK(cx, NULL, "creationTime", file);
@@ -2415,33 +2519,40 @@ file_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
         break;
     default:
         SECURITY_CHECK(cx, NULL, "file_access", file);
-               /* this is some other property -- try to use the dir["file"] syntax */
-        if(js_isDirectory(cx, file)){
-                       PRDir *dir = NULL;
-                       PRDirEntry *entry = NULL;
-            char *prop_name = JS_GetStringBytes(JS_ValueToString(cx, id));
+
+        /* 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);
+                JS_ReportWarning(cx, "Can't open directory %s", file->path);
                 return JS_FALSE;
             }
 
-            while((entry = PR_ReadDir(dir, PR_SKIP_NONE))!=NULL){
-                               if(!strcmp(entry->name, prop_name)){
-                    str = js_combinePath(cx, file->path, prop_name);
-                    *vp = OBJECT_TO_JSVAL(js_NewFileObject(cx, str));
-                                       JS_free(cx, str);
+            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:
-       *vp = JSVAL_VOID;
     return JS_FALSE;
 }
 
@@ -2497,8 +2608,7 @@ file_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
     return JS_TRUE;
 out:
-       *vp = JSVAL_VOID;
-       return JS_FALSE;
+    return JS_FALSE;
 }
 
 /*
@@ -2507,52 +2617,54 @@ out:
 static JSBool
 file_currentDirSetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
-    JSObject *rhsObject;
-    char     *path;
-    JSFile   *file = JS_GetInstancePrivate(cx, rhsObject, &file_class, NULL);
+    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, rhsObject, &file_class, NULL)){
+    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))){
+            if (file && (!js_exists(cx, file) || !js_isDirectory(cx, file))) {
                 JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, vp);
-                goto out;
-            }else{
-                rhsObject = JSVAL_TO_OBJECT(*vp);
+                return JS_FALSE;
+            } else {
                 chdir(file->path);
                 return JS_TRUE;
             }
-        }else
-            goto out;
-    }else{
+        } else {
+            return JS_FALSE;
+        }
+    } else {
+        JSObject *rhsObject;
+        char     *path;
+
         path      = JS_GetStringBytes(JS_ValueToString(cx, *vp));
         rhsObject = js_NewFileObject(cx, path);
-        if (!rhsObject)  goto out;
+        if (!rhsObject)
+            return JS_FALSE;
 
         if (!file || !js_exists(cx, file) || !js_isDirectory(cx, file)){
             JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, vp);
-        }else{
+        } else {
             *vp = OBJECT_TO_JSVAL(rhsObject);
             chdir(path);
         }
     }
+
     return JS_TRUE;
-out:
-       *vp = JSVAL_VOID;
-       return JS_FALSE;
 }
 
 /* Declare class */
 static JSClass file_class = {
     FILE_CONSTRUCTOR, JSCLASS_HAS_PRIVATE,
     JS_PropertyStub,  JS_PropertyStub,  file_getProperty,  file_setProperty,
-    JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   file_finalize
+    JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,    file_finalize
 };
 
 /* -------------------- Functions exposed to the outside -------------------- */
 JS_PUBLIC_API(JSObject*)
-js_InitFileClass(JSContext *cx, JSObject* obj, JSBool initStandardStreams)
+js_InitFileClass(JSContext *cx, JSObject* obj)
 {
     JSObject *file, *ctor, *afile;
     jsval    vp;
@@ -2582,23 +2694,21 @@ js_InitFileClass(JSContext *cx, JSObject* obj, JSBool initStandardStreams)
                 JS_PropertyStub, file_currentDirSetter,
                 JSPROP_ENUMERATE | JSPROP_READONLY );
 
-    if(initStandardStreams){
-        /* Code to create stdin, stdout, and stderr. Insert in the appropriate place. */
-        /* Define input */
-        vp = OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx, stdin,
-                STDINPUT_NAME, PR_RDONLY, JS_TRUE, JS_FALSE));
-        JS_SetProperty(cx, ctor, "input", &vp);
+    /* Define 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 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);
 
-        /* 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));
index 47a8692d8f81be369bef3eca326a82430156983e..741c5bdd02308c0cd84006b81bf0d42ecab52586 100644 (file)
@@ -42,7 +42,7 @@
 
 #if JS_HAS_FILE_OBJECT
 extern JS_PUBLIC_API(JSObject*)
-js_InitFileClass(JSContext *cx, JSObject* obj, JSBool initStandardStreams);
+js_InitFileClass(JSContext *cx, JSObject* obj);
 
 extern JS_PUBLIC_API(JSObject*)
 js_NewFileObject(JSContext *cx, char *bytes);
index f03c51d42d9d5f8d5b961abedd593548b9ec5afd..137b35d874058fe08d0721f6367f6dafe9cfd32e 100644 (file)
@@ -55,6 +55,7 @@ MSG_DEF(JSFILEMSG_CANNOT_FLUSH_CLOSE_FILE_ERROR,                  10, 1, JSEXN_N
 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")
index bbb1e1b61324aa2596f681ca2c4704a9b0aefc5c..68372e1296e4fcab57e0789694afb0846aaa4310 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
@@ -96,7 +97,8 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp)
     if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
         JS_ASSERT(fp->callobj);
         return OBJ_GET_PROPERTY(cx, fp->callobj,
-                                (jsid) cx->runtime->atomState.argumentsAtom,
+                                ATOM_TO_JSID(cx->runtime->atomState
+                                             .argumentsAtom),
                                 vp);
     }
     argsobj = js_GetArgsObject(cx, fp);
@@ -106,9 +108,6 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp)
     return JS_TRUE;
 }
 
-#define MAXARGS(fp)     ((fp)->fun ? JS_MAX((fp)->argc, (fp)->fun->nargs)     \
-                                   : (fp)->argc)
-
 static JSBool
 MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
 {
@@ -119,7 +118,7 @@ MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
 
     argsobj = fp->argsobj;
     (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
-    nbits = MAXARGS(fp);
+    nbits = fp->argc;
     JS_ASSERT(slot < nbits);
     if (JSVAL_IS_VOID(bmapval)) {
         if (nbits <= JSVAL_INT_BITS) {
@@ -162,7 +161,7 @@ ArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
     (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
     if (JSVAL_IS_VOID(bmapval))
         return JS_FALSE;
-    if (MAXARGS(fp) <= JSVAL_INT_BITS) {
+    if (fp->argc <= JSVAL_INT_BITS) {
         bmapint = JSVAL_TO_INT(bmapval);
         bitmap = (jsbitmap *) &bmapint;
     } else {
@@ -182,7 +181,8 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id,
     if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
         JS_ASSERT(fp->callobj);
         if (!OBJ_GET_PROPERTY(cx, fp->callobj,
-                              (jsid) cx->runtime->atomState.argumentsAtom,
+                              ATOM_TO_JSID(cx->runtime->atomState
+                                           .argumentsAtom),
                               &val)) {
             return JS_FALSE;
         }
@@ -199,15 +199,30 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id,
 
     *objp = NULL;
     *vp = JSVAL_VOID;
-    if (JSVAL_IS_INT(id)) {
-        slot = (uintN) JSVAL_TO_INT(id);
-        if (slot < MAXARGS(fp)) {
+    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 == (jsid) cx->runtime->atomState.lengthAtom) {
+        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);
@@ -221,6 +236,10 @@ 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)
@@ -262,7 +281,7 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
     (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
     if (!JSVAL_IS_VOID(bmapval)) {
         JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID);
-        if (MAXARGS(fp) > JSVAL_INT_BITS)
+        if (fp->argc > JSVAL_INT_BITS)
             JS_free(cx, JSVAL_TO_PRIVATE(bmapval));
     }
 
@@ -271,10 +290,14 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
      * before fp goes away.
      */
     rt = cx->runtime;
-    ok &= js_GetProperty(cx, argsobj, (jsid)rt->atomState.calleeAtom, &rval);
-    ok &= js_SetProperty(cx, argsobj, (jsid)rt->atomState.calleeAtom, &rval);
-    ok &= js_GetProperty(cx, argsobj, (jsid)rt->atomState.lengthAtom, &rval);
-    ok &= js_SetProperty(cx, argsobj, (jsid)rt->atomState.lengthAtom, &rval);
+    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).
@@ -308,7 +331,7 @@ args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
         break;
 
       default:
-        if ((uintN)slot < MAXARGS(fp) && !MarkArgDeleted(cx, fp, slot))
+        if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot))
             return JS_FALSE;
         break;
     }
@@ -342,7 +365,7 @@ args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
         break;
 
       default:
-        if ((uintN)slot < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot))
+        if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot))
             *vp = fp->argv[slot];
         break;
     }
@@ -371,8 +394,11 @@ args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
         break;
 
       default:
-        if ((uintN)slot < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot))
+        if (fp->fun->interpreted &&
+            (uintN)slot < fp->argc &&
+            !ArgWasDeleted(cx, fp, slot)) {
             fp->argv[slot] = *vp;
+        }
         break;
     }
     return JS_TRUE;
@@ -398,11 +424,12 @@ args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
 
     if (JSVAL_IS_INT(id)) {
         slot = JSVAL_TO_INT(id);
-        if (slot < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot)) {
+        if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) {
             /* XXX ECMA specs DontEnum, contrary to other array-like objects */
-            if (!js_DefineProperty(cx, obj, (jsid) id, fp->argv[slot],
+            if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id),
+                                   fp->argv[slot],
                                    args_getProperty, args_setProperty,
-                                   JSVERSION_IS_ECMA(cx->version)
+                                   JS_VERSION_IS_ECMA(cx)
                                    ? 0
                                    : JSPROP_ENUMERATE,
                                    NULL)) {
@@ -432,7 +459,7 @@ args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
         }
 
         if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
-            if (!js_DefineNativeProperty(cx, obj, (jsid) atom, value,
+            if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
                                          args_getProperty, args_setProperty, 0,
                                          SPROP_HAS_SHORTID, tinyid, NULL)) {
                 return JS_FALSE;
@@ -450,7 +477,7 @@ args_enumerate(JSContext *cx, JSObject *obj)
     JSStackFrame *fp;
     JSObject *pobj;
     JSProperty *prop;
-    uintN slot, nargs;
+    uintN slot, argc;
 
     fp = (JSStackFrame *)
          JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
@@ -465,26 +492,26 @@ args_enumerate(JSContext *cx, JSObject *obj)
      * and creates direct properties of obj, but that it may fail to resolve
      * length or callee if overridden.
      */
-    if (!js_LookupProperty(cx, obj, (jsid) cx->runtime->atomState.lengthAtom,
+    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, (jsid) cx->runtime->atomState.calleeAtom,
+    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);
 
-    nargs = MAXARGS(fp);
-    for (slot = 0; slot < nargs; slot++) {
-        if (!js_LookupProperty(cx, obj, (jsid) INT_TO_JSVAL((jsint)slot),
-                               &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);
     }
@@ -573,7 +600,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
      * Get the arguments object to snapshot fp's actual argument values.
      */
     if (fp->argsobj) {
-        argsid = (jsid) cx->runtime->atomState.argumentsAtom;
+        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);
@@ -695,11 +722,12 @@ static JSBool
 call_enumerate(JSContext *cx, JSObject *obj)
 {
     JSStackFrame *fp;
-    JSObject *funobj;
+    JSObject *funobj, *pobj;
     JSScope *scope;
     JSScopeProperty *sprop, *cprop;
     JSPropertyOp getter;
     jsval *vec;
+    JSAtom *atom;
     JSProperty *prop;
 
     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
@@ -737,12 +765,28 @@ call_enumerate(JSContext *cx, JSObject *obj)
         else
             continue;
 
-        /* Trigger reflection in call_resolve by doing a lookup. */
-        if (!js_LookupProperty(cx, obj, sprop->id, &obj, &prop))
+        /* 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;
-        JS_ASSERT(obj && prop);
+
+        /*
+         * 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[sprop->shortid]);
+        LOCKED_OBJ_SET_SLOT(obj, cprop->slot, vec[(uint16) sprop->shortid]);
         OBJ_DROP_PROPERTY(cx, obj, prop);
     }
 
@@ -760,7 +804,6 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
     JSObject *obj2;
     JSProperty *prop;
     JSScopeProperty *sprop;
-    jsid propid;
     JSPropertyOp getter, setter;
     uintN attrs, slot, nslots, spflags;
     jsval *vp, value;
@@ -777,27 +820,37 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
     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_LookupProperty(cx, funobj, (jsid)atom, &obj2, &prop))
+    if (!js_LookupHiddenProperty(cx, funobj, ATOM_TO_JSID(atom), &obj2, &prop))
         return JS_FALSE;
 
-    sprop = (JSScopeProperty *) prop;
-    if (sprop && OBJ_IS_NATIVE(obj2)) {
-        propid = sprop->id;
+    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);
-        if (getter == js_GetArgument || getter == js_GetLocalVariable) {
+
+        /* 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;
@@ -812,7 +865,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
                 spflags = 0;
                 shortid = 0;
             }
-            if (!js_DefineNativeProperty(cx, obj, propid, value,
+            if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
                                          getter, setter, attrs,
                                          spflags, shortid, NULL)) {
                 return JS_FALSE;
@@ -820,6 +873,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
             *objp = obj;
         }
     }
+
     return JS_TRUE;
 }
 
@@ -850,15 +904,25 @@ JSClass js_CallClass = {
 
 #endif /* JS_HAS_CALL_OBJECT */
 
-/* SHARED because fun_getProperty always computes a new value. */
-#define FUNCTION_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
+/*
+ * 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, FUNCTION_PROP_ATTRS,0,0},
-    {js_arity_str,     FUN_ARITY,      FUNCTION_PROP_ATTRS,0,0},
-    {js_length_str,    ARGS_LENGTH,    FUNCTION_PROP_ATTRS,0,0},
-    {js_name_str,      FUN_NAME,       FUNCTION_PROP_ATTRS,0,0},
-    {js_caller_str,    FUN_CALLER,     FUNCTION_PROP_ATTRS,0,0},
+    {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}
 };
 
@@ -873,10 +937,34 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
         return JS_TRUE;
     slot = JSVAL_TO_INT(id);
 
-    /* No valid function object should lack private data, but check anyway. */
-    fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
-    if (!fun)
-        return JS_TRUE;
+    /*
+     * 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));
@@ -908,7 +996,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 #endif /* !JS_HAS_ARGS_OBJECT */
 
       case ARGS_LENGTH:
-        if (!JSVERSION_IS_ECMA(cx->version))
+        if (!JS_VERSION_IS_ECMA(cx))
             *vp = INT_TO_JSVAL((jsint)(fp && fp->fun ? fp->argc : fun->nargs));
         else
       case FUN_ARITY:
@@ -945,6 +1033,21 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
     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)
@@ -981,15 +1084,24 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
              * Clone of a function: make its prototype property value have the
              * same class as the clone-parent's prototype.
              */
-            if (!OBJ_GET_PROPERTY(cx, fun->object, (jsid)prototypeAtom, &pval))
+            if (!OBJ_GET_PROPERTY(cx, fun->object, ATOM_TO_JSID(prototypeAtom),
+                                  &pval)) {
                 return JS_FALSE;
-            if (JSVAL_IS_OBJECT(pval))
+            }
+            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.
+         * to find a prototype for that will recur back here _ad perniciem_.
          */
         if (!parentProto && fun->atom == cx->runtime->atomState.ObjectAtom)
             return JS_TRUE;
@@ -1048,9 +1160,10 @@ fun_finalize(JSContext *cx, JSObject *obj)
     JS_ATOMIC_DECREMENT(&fun->nrefs);
     if (fun->nrefs)
         return;
-    if (fun->interpreted)
+
+    /* Null-check required since the parser sets interpreted very early. */
+    if (fun->interpreted && fun->u.script)
         js_DestroyScript(cx, fun->u.script);
-    JS_free(cx, fun);
 }
 
 #if JS_HAS_XDR
@@ -1070,6 +1183,7 @@ 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;
@@ -1077,6 +1191,7 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
     JSAtom *atom;
     uintN i, n, dupflag;
     uint32 type;
+    JSBool ok;
 #ifdef DEBUG
     uintN nvars = 0, nargs = 0;
 #endif
@@ -1106,12 +1221,16 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
         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)) {
-        return JS_FALSE;
+        goto bad;
     }
 
     /* do arguments and local vars */
@@ -1131,7 +1250,7 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
                                        n * sizeof(JSScopeProperty *));
                 if (!spvec) {
                     JS_ReportOutOfMemory(cx);
-                    return JS_FALSE;
+                    goto bad;
                 }
             }
             scope = OBJ_SCOPE(fun->object);
@@ -1155,14 +1274,14 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
                        : JSXDR_FUNVAR;
                 userid = INT_TO_JSVAL(sprop->shortid);
                 /* XXX lossy conversion, need new XDR version for ECMAv3 */
-                propname = JS_GetStringBytes(ATOM_TO_STRING((JSAtom *)sprop->id));
+                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);
-                    return JS_FALSE;
+                    goto bad;
                 }
             }
             if (mark)
@@ -1171,12 +1290,12 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
             JSPropertyOp getter, setter;
 
             for (i = n; i != 0; i--) {
-                uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
+                uintN attrs = JSPROP_PERMANENT;
 
                 if (!JS_XDRUint32(xdr, &type) ||
                     !JS_XDRUint32(xdr, &userid) ||
                     !JS_XDRCString(xdr, &propname)) {
-                    return JS_FALSE;
+                    goto bad;
                 }
                 JS_ASSERT(type == JSXDR_FUNARG || type == JSXDR_FUNVAR ||
                           type == JSXDR_FUNCONST);
@@ -1197,26 +1316,27 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
                 atom = js_Atomize(cx, propname, strlen(propname), 0);
                 JS_free(cx, propname);
                 if (!atom)
-                    return JS_FALSE;
+                    goto bad;
 
                 /* Flag duplicate argument if atom is bound in fun->object. */
-                dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object), (jsid)atom)
+                dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object),
+                                             ATOM_TO_JSID(atom))
                           ? SPROP_IS_DUPLICATE
                           : 0;
 
-                if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
+                if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom),
                                           getter, setter, SPROP_INVALID_SLOT,
                                           attrs | JSPROP_SHARED,
-                                          SPROP_HAS_SHORTID | dupflag,
+                                          dupflag | SPROP_HAS_SHORTID,
                                           JSVAL_TO_INT(userid))) {
-                    return JS_FALSE;
+                    goto bad;
                 }
             }
         }
     }
 
     if (!js_XDRScript(xdr, &fun->u.script, NULL))
-        return JS_FALSE;
+        goto bad;
 
     if (xdr->mode == JSXDR_DECODE) {
         fun->interpreted = JS_TRUE;
@@ -1228,13 +1348,19 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
             /* XXX only if this was a top-level function! */
             fun->atom = js_AtomizeString(cx, atomstr, 0);
             if (!fun->atom)
-                return JS_FALSE;
+                goto bad;
         }
 
         js_CallNewScriptHook(cx, fun->u.script, fun);
     }
 
-    return JS_TRUE;
+out:
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return ok;
+
+bad:
+    ok = JS_FALSE;
+    goto out;
 }
 
 #else  /* !JS_HAS_XDR */
@@ -1257,7 +1383,8 @@ fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
     JSString *str;
 
     if (!OBJ_GET_PROPERTY(cx, obj,
-                          (jsid)cx->runtime->atomState.classPrototypeAtom,
+                          ATOM_TO_JSID(cx->runtime->atomState
+                                       .classPrototypeAtom),
                           &pval)) {
         return JS_FALSE;
     }
@@ -1291,9 +1418,10 @@ fun_mark(JSContext *cx, JSObject *obj, void *arg)
 
     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)
+        if (fun->interpreted && fun->u.script)
             js_MarkScript(cx, fun->u.script, arg);
     }
     return 0;
@@ -1313,12 +1441,12 @@ fun_reserveSlots(JSContext *cx, JSObject *obj)
  * does not bloat every instance, only those on which reserved slots are set,
  * and those on which ad-hoc properties are defined.
  */
-JSClass js_FunctionClass = {
+JS_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,
-    JS_EnumerateStub, (JSResolveOp)fun_resolve,
+    fun_enumerate,    (JSResolveOp)fun_resolve,
     fun_convert,      fun_finalize,
     NULL,             NULL,
     NULL,             NULL,
@@ -1349,6 +1477,7 @@ js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent,
                                                      &fval)) {
                     return JS_FALSE;
                 }
+                argv[-1] = fval;
             }
             if (!JSVAL_IS_FUNCTION(cx, fval)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@@ -1389,13 +1518,14 @@ fun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 }
 #endif
 
-static const char js_call_str[] = "call";
+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;
@@ -1406,16 +1536,19 @@ fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     fval = argv[-1];
 
     if (!JSVAL_IS_FUNCTION(cx, fval)) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                             JSMSG_INCOMPATIBLE_PROTO,
-                             js_Function_str, js_call_str,
-                             JS_GetStringBytes(JS_ValueToString(cx, fval)));
+        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 parent as the 'this' parameter if no args. */
-        obj = OBJ_GET_PARENT(cx, obj);
+        /* 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))
@@ -1454,6 +1587,7 @@ 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;
@@ -1471,10 +1605,13 @@ fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     fval = argv[-1];
 
     if (!JSVAL_IS_FUNCTION(cx, fval)) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                             JSMSG_INCOMPATIBLE_PROTO,
-                             js_Function_str, "apply",
-                             JS_GetStringBytes(JS_ValueToString(cx, fval)));
+        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;
     }
 
@@ -1546,7 +1683,7 @@ static JSFunctionSpec function_methods[] = {
     {"apply",           fun_apply,      2,0,0},
 #endif
 #if JS_HAS_CALL_FUNCTION
-    {js_call_str,       fun_call,       1,0,0},
+    {call_str,          fun_call,       1,0,0},
 #endif
     {0,0,0,0,0}
 };
@@ -1562,7 +1699,7 @@ js_IsIdentifier(JSString *str)
         return JS_FALSE;
     s = JSSTRING_CHARS(str);
     c = *s;
-    if (!JS_ISIDENT_START(c))
+    if (!JS_ISIDSTART(c))
         return JS_FALSE;
     for (n--; n != 0; n--) {
         c = *++s;
@@ -1589,7 +1726,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     JSTokenStream *ts;
     JSPrincipals *principals;
     jschar *collected_args, *cp;
-    size_t arg_length, args_length;
+    size_t arg_length, args_length, old_args_length;
     JSTokenType tt;
     JSBool ok;
 
@@ -1622,7 +1759,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 #endif
 
     fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA, parent,
-                         JSVERSION_IS_ECMA(cx->version)
+                         JS_VERSION_IS_ECMA(cx)
                          ? cx->runtime->atomState.anonymousAtom
                          : NULL);
 
@@ -1648,6 +1785,10 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         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) {
         /*
@@ -1667,10 +1808,27 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             if (!arg)
                 return JS_FALSE;
             argv[i] = STRING_TO_JSVAL(arg);
-            args_length += JSSTRING_LENGTH(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;
         }
-        /* Add 1 for each joining comma. */
-        args_length += n - 1;
 
         /*
          * Allocate a string to hold the concatenated arguments, including room
@@ -1680,8 +1838,10 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         mark = JS_ARENA_MARK(&cx->tempPool);
         JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
                                (args_length+1) * sizeof(jschar));
-        if (!cp)
+        if (!cp) {
+            JS_ReportOutOfMemory(cx);
             return JS_FALSE;
+        }
         collected_args = cp;
 
         /*
@@ -1724,8 +1884,10 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                  * we're assured at this point that it's a valid identifier.
                  */
                 atom = CURRENT_TOKEN(ts).t_atom;
-                if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2, &prop))
+                if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom),
+                                             &obj2, &prop)) {
                     goto bad_formal;
+                }
                 sprop = (JSScopeProperty *) prop;
                 dupflag = 0;
                 if (sprop) {
@@ -1741,7 +1903,8 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                          */
                         JS_ASSERT(sprop->getter == js_GetArgument);
                         ok = name &&
-                             js_ReportCompileErrorNumber(cx, ts, NULL,
+                             js_ReportCompileErrorNumber(cx, ts,
+                                                         JSREPORT_TS |
                                                          JSREPORT_WARNING |
                                                          JSREPORT_STRICT,
                                                          JSMSG_DUPLICATE_FORMAL,
@@ -1754,15 +1917,19 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                         goto bad_formal;
                     sprop = NULL;
                 }
-                if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
+                if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom),
                                           js_GetArgument, js_SetArgument,
                                           SPROP_INVALID_SLOT,
-                                          JSPROP_ENUMERATE | JSPROP_PERMANENT |
-                                          JSPROP_SHARED,
-                                          SPROP_HAS_SHORTID | dupflag,
+                                          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++;
 
                 /*
@@ -1818,6 +1985,7 @@ bad_formal:
     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.
@@ -1860,8 +2028,19 @@ bad:
 JSObject *
 js_InitCallClass(JSContext *cx, JSObject *obj)
 {
-    return JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,
-                        call_props, NULL, NULL, NULL);
+    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
 
@@ -1870,23 +2049,28 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
                uintN flags, JSObject *parent, JSAtom *atom)
 {
     JSFunction *fun;
-
-    /* Allocate a function struct. */
-    fun = (JSFunction *) JS_malloc(cx, sizeof *fun);
-    if (!fun)
-        return NULL;
+    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) {
-            JS_free(cx, fun);
+        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;
@@ -1904,9 +2088,11 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
     /* Link fun to funobj and vice versa. */
     if (!js_LinkFunctionObject(cx, fun, funobj)) {
         cx->newborn[GCX_OBJECT] = NULL;
-        JS_free(cx, fun);
-        return NULL;
+        fun = NULL;
     }
+
+out:
+    JS_POP_TEMP_ROOT(cx, &tvr);
     return fun;
 }
 
@@ -1948,8 +2134,10 @@ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
     fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
     if (!fun)
         return NULL;
-    if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, OBJECT_TO_JSVAL(fun->object),
-                             NULL, NULL, attrs & ~JSFUN_FLAGS_MASK, NULL)) {
+    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;
@@ -1982,6 +2170,61 @@ js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
     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)
 {
index eb79161a90f58710a78e2440cd3659dfab0a6033..25aa10320a5e58889ebacbef3b0553eebe48bdbc 100644 (file)
@@ -48,7 +48,7 @@
 JS_BEGIN_EXTERN_C
 
 struct JSFunction {
-    jsrefcount  nrefs;         /* number of referencing objects */
+    jsrefcount   nrefs;         /* number of referencing objects */
     JSObject     *object;       /* back-pointer to GC'ed object header */
     union {
         JSNative native;        /* native method pointer or null */
@@ -78,7 +78,7 @@ extern JS_FRIEND_DATA(JSClass) js_FunctionClass;
  * NB: jsapi.h and jsobj.h must be included before any call to this macro.
  */
 #define JSVAL_IS_FUNCTION(cx, v)                                              \
-    (JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) &&                              \
+    (!JSVAL_IS_PRIMITIVE(v) &&                                                \
      OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass)
 
 extern JSBool
@@ -99,7 +99,7 @@ js_InitCallClass(JSContext *cx, JSObject *obj);
 
 extern JSFunction *
 js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
-              uintN flags, JSObject *parent, JSAtom *atom);
+               uintN flags, JSObject *parent, JSAtom *atom);
 
 extern JSObject *
 js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
@@ -109,7 +109,7 @@ js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *object);
 
 extern JSFunction *
 js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
-                 uintN nargs, uintN flags);
+                  uintN nargs, uintN flags);
 
 /*
  * Flags for js_ValueToFunction and js_ReportIsNotFunction.  We depend on the
@@ -122,6 +122,12 @@ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
 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);
 
index 754f4ae6d1fb4609b99ee56b54d9df1ae5b52904..2383240c7edbe892455b467e49019f6b76068175 100644 (file)
 #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.
 #define GC_FLAGS_SIZE   (GC_THINGS_SIZE / sizeof(JSGCThing))
 #define GC_ARENA_SIZE   (GC_THINGS_SIZE + GC_FLAGS_SIZE)
 
-/*
- * The private JSGCThing struct, which describes a gcFreeList element.
- */
-struct JSGCThing {
-    JSGCThing   *next;
-    uint8       *flagp;
-};
-
 /*
  * A GC arena contains one flag byte for each thing in its heap, and supports
  * O(1) lookup of a flag given its thing's address.
@@ -175,11 +171,26 @@ typedef struct 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)
+gc_new_arena(JSArenaPool *pool, size_t nbytes)
 {
     uint8 *flagp, *split, *pagep, *limit;
     JSArena *a;
+    jsuword p;
     JSGCThing *thing;
     JSGCPageInfo *pi;
 
@@ -190,11 +201,13 @@ gc_new_arena(JSArenaPool *pool)
     a = pool->current;
 
     /* Reset a->avail to start at the flags split, aka the first thing page. */
-    a->avail = FIRST_THING_PAGE(a);
-    split = pagep = (uint8 *) a->avail;
-    a->avail += sizeof(JSGCPageInfo);
+    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;
-    a->avail += sizeof(JSGCThing);
+    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;
@@ -226,12 +239,62 @@ js_IsAboutToBeFinalized(JSContext *cx, void *thing)
 {
     uint8 flags = *js_GetGCThingFlags(thing);
 
-    return !(flags & (GCF_MARK | GCF_LOCKMASK | GCF_FINAL));
+    return !(flags & (GCF_MARK | GCF_LOCK | GCF_FINAL));
 }
 
 typedef void (*GCFinalizeOp)(JSContext *cx, JSGCThing *thing);
 
-static GCFinalizeOp gc_finalizers[GCX_NTYPES];
+#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,
@@ -261,6 +324,8 @@ js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
 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));
@@ -268,50 +333,65 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
     JS_ASSERT(GC_FLAGS_SIZE >= GC_PAGE_SIZE);
     JS_ASSERT(sizeof(JSStackHeader) >= 2 * sizeof(jsval));
 
-    if (!gc_finalizers[GCX_OBJECT]) {
-        gc_finalizers[GCX_OBJECT] = (GCFinalizeOp)js_FinalizeObject;
-        gc_finalizers[GCX_STRING] = (GCFinalizeOp)js_FinalizeString;
-#ifdef DEBUG
-        gc_finalizers[GCX_DOUBLE] = (GCFinalizeOp)js_FinalizeDouble;
-#endif
-        gc_finalizers[GCX_MUTABLE_STRING] = (GCFinalizeOp)js_FinalizeString;
-    }
-
-    JS_InitArenaPool(&rt->gcArenaPool, "gc-arena", GC_ARENA_SIZE,
-                     sizeof(JSGCThing));
+    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 */
-    rt->gcMaxBytes = maxbytes;
+
+    /*
+     * Separate gcMaxMallocBytes from gcMaxBytes but initialize to maxbytes
+     * for default backward API compatibility.
+     */
+    rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes;
     return JS_TRUE;
 }
 
 #ifdef JS_GCMETER
-void
+JS_FRIEND_API(void)
 js_DumpGCStats(JSRuntime *rt, FILE *fp)
 {
+    uintN i;
+
     fprintf(fp, "\nGC allocation statistics:\n");
-    fprintf(fp, "     bytes currently allocated: %lu\n", rt->gcBytes);
-    fprintf(fp, "                alloc attempts: %lu\n", rt->gcStats.alloc);
-    fprintf(fp, "            GC freelist length: %lu\n", rt->gcStats.freelen);
-    fprintf(fp, "  recycles through GC freelist: %lu\n", rt->gcStats.recycle);
-    fprintf(fp, "alloc retries after running GC: %lu\n", rt->gcStats.retry);
-    fprintf(fp, "           allocation failures: %lu\n", rt->gcStats.fail);
-    fprintf(fp, "              valid lock calls: %lu\n", rt->gcStats.lock);
-    fprintf(fp, "            valid unlock calls: %lu\n", rt->gcStats.unlock);
-    fprintf(fp, "   locks that hit stuck counts: %lu\n", rt->gcStats.stuck);
-    fprintf(fp, " unlocks that saw stuck counts: %lu\n", rt->gcStats.unstuck);
-    fprintf(fp, "          mark recursion depth: %lu\n", rt->gcStats.depth);
-    fprintf(fp, "  maximum mark recursion depth: %lu\n", rt->gcStats.maxdepth);
-    fprintf(fp, "      maximum GC nesting level: %lu\n", rt->gcStats.maxlevel);
-    fprintf(fp, "   potentially useful GC calls: %lu\n", rt->gcStats.poke);
-    fprintf(fp, "              useless GC calls: %lu\n", rt->gcStats.nopoke);
-    fprintf(fp, "     thing arenas freed so far: %lu\n", rt->gcStats.afree);
-    fprintf(fp, "  extra stack segments scanned: %lu\n", rt->gcStats.stackseg);
-    fprintf(fp, "   stack segment slots scanned: %lu\n", rt->gcStats.segslots);
+
+#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
@@ -337,13 +417,18 @@ js_root_printer(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 i, void *arg)
 void
 js_FinishGC(JSRuntime *rt)
 {
+    uintN i;
+
 #ifdef JS_ARENAMETER
     JS_DumpArenaStats(stdout);
 #endif
 #ifdef JS_GCMETER
     js_DumpGCStats(rt, stdout);
 #endif
-    JS_FinishArenaPool(&rt->gcArenaPool);
+    for (i = 0; i < GC_NUM_FREELISTS; i++) {
+        JS_FinishArenaPool(&rt->gcArenaPool[i]);
+        rt->gcFreeList[i] = NULL;
+    }
     JS_ArenaFinish();
 
     if (rt->gcRootsHash.ops) {
@@ -376,7 +461,6 @@ js_FinishGC(JSRuntime *rt)
         JS_DHashTableDestroy(rt->gcLocksHash);
         rt->gcLocksHash = NULL;
     }
-    rt->gcFreeList = NULL;
 }
 
 JSBool
@@ -451,21 +535,28 @@ js_RemoveRoot(JSRuntime *rt, void *rp)
     return JS_TRUE;
 }
 
+#ifdef DEBUG_brendan
+#define NGCHIST 64
+
+static struct GCHist {
+    JSBool      lastDitch;
+    JSGCThing   *freeList;
+} gchist[NGCHIST];
+
+unsigned gchpos;
+#endif
+
 void *
-js_AllocGCThing(JSContext *cx, uintN flags)
+js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
 {
     JSBool tried_gc;
     JSRuntime *rt;
-    JSGCThing *thing;
+    size_t nflags;
+    uintN i;
+    JSGCThing *thing, **flp;
     uint8 *flagp;
     JSLocalRootStack *lrs;
-
-#ifdef TOO_MUCH_GC
-    js_GC(cx, GC_KEEP_ATOMS);
-    tried_gc = JS_TRUE;
-#else
-    tried_gc = JS_FALSE;
-#endif
+    uint32 *bytesptr;
 
     rt = cx->runtime;
     JS_LOCK_GC(rt);
@@ -475,17 +566,33 @@ js_AllocGCThing(JSContext *cx, uintN flags)
         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 = rt->gcFreeList;
+    thing = *flp;
     if (thing) {
-        rt->gcFreeList = thing->next;
+        *flp = thing->next;
         flagp = thing->flagp;
-        METER(rt->gcStats.freelen--);
-        METER(rt->gcStats.recycle++);
+        METER(rt->gcStats.freelen[i]--);
+        METER(rt->gcStats.recycle[i]++);
     } else {
         if (rt->gcBytes < rt->gcMaxBytes &&
-            (tried_gc || rt->gcMallocBytes < rt->gcMaxBytes))
+            (tried_gc || rt->gcMallocBytes < rt->gcMaxMallocBytes))
         {
             /*
              * Inline form of JS_ARENA_ALLOCATE adapted to truncate the current
@@ -493,25 +600,24 @@ retry:
              * GC_PAGE_SIZE-byte-aligned thing (which is actually not a thing,
              * it's a JSGCPageInfo record).
              */
-            JSArenaPool *pool = &rt->gcArenaPool;
+            JSArenaPool *pool = &rt->gcArenaPool[i];
             JSArena *a = pool->current;
-            size_t nb = sizeof(JSGCThing);
             jsuword p = a->avail;
-            jsuword q = p + nb;
+            jsuword q = p + nbytes;
 
             if (q > (a->limit & ~GC_PAGE_MASK)) {
-                thing = gc_new_arena(pool);
+                thing = gc_new_arena(pool, nbytes);
             } else {
                 if ((p & GC_PAGE_MASK) == 0) {
                     /* Beware, p points to a JSGCPageInfo record! */
-                    p = q;
-                    q += nb;
-                    JS_ArenaCountAllocation(pool, nb);
+                    p = FIRST_THING(p, nbytes);
+                    q = p + nbytes;
+                    JS_ArenaCountAllocation(pool, p & GC_PAGE_MASK);
                 }
                 a->avail = q;
                 thing = (JSGCThing *)p;
             }
-            JS_ArenaCountAllocation(pool, nb);
+            JS_ArenaCountAllocation(pool, nbytes);
         }
 
         /*
@@ -548,8 +654,17 @@ retry:
          * 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)
+        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
@@ -558,9 +673,12 @@ retry:
         cx->newborn[flags & GCF_TYPEMASK] = thing;
     }
 
-    /* We can't fail now, so update flags and rt->gcBytes. */
+    /* We can't fail now, so update flags and rt->gc{,Private}Bytes. */
     *flagp = (uint8)flags;
-    rt->gcBytes += sizeof(JSGCThing) + sizeof(uint8);
+    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,
@@ -568,6 +686,13 @@ retry:
      */
     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;
 
@@ -587,69 +712,85 @@ js_LockGCThing(JSContext *cx, void *thing)
     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)
 {
-    uint8 *flagp, flags, lockbits;
-    JSBool ok;
+    JSBool ok, deep;
+    uint8 *flagp, flags, lock, type;
     JSGCLockHashEntry *lhe;
 
+    ok = JS_TRUE;
     if (!thing)
-        return JS_TRUE;
+        return ok;
+
     flagp = js_GetGCThingFlags(thing);
-    flags = *flagp;
 
-    ok = JS_FALSE;
     JS_LOCK_GC(rt);
-    lockbits = (flags & GCF_LOCKMASK);
-
-    if (lockbits != GCF_LOCKMASK) {
-        if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {
-            /* Objects may require "deep locking", i.e., rooting by value. */
-            if (lockbits == 0) {
-                if (!rt->gcLocksHash) {
-                    rt->gcLocksHash =
-                        JS_NewDHashTable(JS_DHashGetStubOps(), NULL,
-                                         sizeof(JSGCLockHashEntry),
-                                         GC_ROOTS_SIZE);
-                    if (!rt->gcLocksHash)
-                        goto error;
-                } else {
+    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));
+            JSDHashEntryHdr *hdr =
+                JS_DHashTableOperate(rt->gcLocksHash, thing,
+                                     JS_DHASH_LOOKUP);
+            JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(hdr));
 #endif
-                }
-                lhe = (JSGCLockHashEntry *)
-                    JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_ADD);
-                if (!lhe)
-                    goto error;
-                lhe->thing = thing;
-                lhe->count = 1;
-                *flagp = (uint8)(flags + GCF_LOCK);
-            } else {
-                JS_ASSERT(lockbits == GCF_LOCK);
-                lhe = (JSGCLockHashEntry *)
-                    JS_DHashTableOperate(rt->gcLocksHash, thing,
-                                         JS_DHASH_LOOKUP);
-                JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr));
-                if (JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr)) {
-                    JS_ASSERT(lhe->count >= 1);
-                    lhe->count++;
-                }
-            }
+        }
+
+        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 {
-            *flagp = (uint8)(flags + GCF_LOCK);
+            JS_ASSERT(lhe->count >= 1);
+            lhe->count++;
         }
-    } else {
-        METER(rt->gcStats.stuck++);
     }
 
+    *flagp = (uint8)(flags | GCF_LOCK);
     METER(rt->gcStats.lock++);
     ok = JS_TRUE;
-error:
+done:
     JS_UNLOCK_GC(rt);
     return ok;
 }
@@ -657,41 +798,35 @@ error:
 JSBool
 js_UnlockGCThingRT(JSRuntime *rt, void *thing)
 {
-    uint8 *flagp, flags, lockbits;
+    uint8 *flagp, flags;
     JSGCLockHashEntry *lhe;
 
     if (!thing)
         return JS_TRUE;
+
     flagp = js_GetGCThingFlags(thing);
+    JS_LOCK_GC(rt);
     flags = *flagp;
 
-    JS_LOCK_GC(rt);
-    lockbits = (flags & GCF_LOCKMASK);
-
-    if (lockbits != GCF_LOCKMASK) {
-        if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {
-            /* Defend against a call on an unlocked object. */
-            if (lockbits != 0) {
-                JS_ASSERT(lockbits == GCF_LOCK);
-                lhe = (JSGCLockHashEntry *)
-                    JS_DHashTableOperate(rt->gcLocksHash, thing,
-                                         JS_DHASH_LOOKUP);
-                JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr));
-                if (JS_DHASH_ENTRY_IS_BUSY(&lhe->hdr) &&
-                    --lhe->count == 0) {
-                    (void) JS_DHashTableOperate(rt->gcLocksHash, thing,
-                                                JS_DHASH_REMOVE);
-                    *flagp = (uint8)(flags & ~GCF_LOCKMASK);
-                }
-            }
+    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 {
-            *flagp = (uint8)(flags - GCF_LOCK);
+            /* 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);
         }
-    } else {
-        METER(rt->gcStats.unstuck++);
+        *flagp = (uint8)(flags & ~GCF_LOCK);
     }
 
     rt->gcPoke = JS_TRUE;
+out:
     METER(rt->gcStats.unlock++);
     JS_UNLOCK_GC(rt);
     return JS_TRUE;
@@ -700,7 +835,6 @@ js_UnlockGCThingRT(JSRuntime *rt, void *thing)
 #ifdef GC_MARK_DEBUG
 
 #include <stdio.h>
-#include <stdlib.h>
 #include "jsprf.h"
 
 JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
@@ -771,9 +905,17 @@ gc_dump_thing(JSGCThing *thing, uint8 flags, GCMarkNode *prev, FILE *fp)
         prev = prev->prev;
     }
     while (next) {
-        path = JS_sprintf_append(path, "%s(%s).",
-                                 next->name,
-                                 gc_object_class_name(next->thing));
+        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)
@@ -792,9 +934,36 @@ gc_dump_thing(JSGCThing *thing, uint8 flags, GCMarkNode *prev, FILE *fp)
         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;
@@ -835,24 +1004,41 @@ js_MarkAtom(JSContext *cx, JSAtom *atom, void *arg)
 #endif
         GC_MARK(cx, JSVAL_TO_GCTHING(key), name, arg);
     }
+    if (atom->flags & ATOM_HIDDEN)
+        js_MarkAtom(cx, atom->entry.value, arg);
 }
 
-void
-js_MarkGCThing(JSContext *cx, void *thing, void *arg)
-{
-    uint8 flags, *flagp;
-    JSRuntime *rt;
-    JSObject *obj;
-    uint32 nslots;
-    jsval v, *vp, *end;
-    JSString *str;
+/*
+ * 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
-    JSScope *scope;
-    JSScopeProperty *sprop;
+# 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;
+        return NULL;
 
     flagp = js_GetGCThingFlags(thing);
     flags = *flagp;
@@ -863,85 +1049,194 @@ js_MarkGCThing(JSContext *cx, void *thing, void *arg)
 #endif
 
     if (flags & GCF_MARK)
-        return;
+        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;
 
-    *flagp |= GCF_MARK;
     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, flags, arg, js_DumpGCHeap);
+        gc_dump_thing(thing, *flagp, arg, js_DumpGCHeap);
 #endif
 
-    switch (flags & GCF_TYPEMASK) {
+    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) {
-            /* If obj->slots is null, obj must be a newborn. */
-            JS_ASSERT(!obj->map);
+        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;
         }
-        nslots = (obj->map->ops->mark)
-                 ? obj->map->ops->mark(cx, obj, arg)
-                 : JS_MIN(obj->map->freeslot, obj->map->nslots);
+
+        /* 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 (end = vp + nslots; vp < end; vp++) {
-            v = *vp;
-            if (JSVAL_IS_GCTHING(v)) {
+        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
-                char name[32];
-
-                if (scope) {
-                    uint32 slot;
-                    jsval nval;
-
-                    slot = vp - obj->slots;
-                    for (sprop = SCOPE_LAST_PROP(scope); ;
-                         sprop = sprop->parent) {
-                        if (!sprop) {
-                            switch (slot) {
-                              case JSSLOT_PROTO:
-                                strcpy(name, "__proto__");
-                                break;
-                              case JSSLOT_PARENT:
-                                strcpy(name, "__parent__");
-                                break;
-                              case JSSLOT_PRIVATE:
-                                strcpy(name, "__private__");
-                                break;
-                              default:
-                                JS_snprintf(name, sizeof name,
-                                            "**UNKNOWN SLOT %ld**",
-                                            (long)slot);
-                                break;
-                            }
+            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;
-                        }
-                        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**");
-                            }
+                          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
-                GC_MARK(cx, JSVAL_TO_GCTHING(v), name, arg);
+            } 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;
 
@@ -954,13 +1249,206 @@ js_MarkGCThing(JSContext *cx, void *thing, void *arg)
 
       case GCX_MUTABLE_STRING:
         str = (JSString *)thing;
-        if (JSSTRING_IS_DEPENDENT(str))
-            GC_MARK(cx, JSSTRDEP_BASE(str), "base", arg);
+        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--);
+    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)
@@ -974,16 +1462,19 @@ gc_root_marker(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, void *arg)
     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 (a = cx->runtime->gcArenaPool.first.next; a; a = a->next) {
-            firstpage = FIRST_THING_PAGE(a);
-            if (JS_UPTRDIFF(thing, firstpage) < a->avail - firstpage) {
-                root_points_to_gcArenaPool = JS_TRUE;
-                break;
+        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) {
@@ -1044,10 +1535,13 @@ js_GC(JSContext *cx, uintN gcflags)
     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;
@@ -1082,7 +1576,7 @@ js_GC(JSContext *cx, uintN gcflags)
     if (!(gcflags & GC_ALREADY_LOCKED))
         JS_LOCK_GC(rt);
 
-    /* Do nothing if no assignment has executed since the last GC. */
+    /* Do nothing if no mutator has executed since the last GC. */
     if (!rt->gcPoke) {
         METER(rt->gcStats.nopoke++);
         if (!(gcflags & GC_ALREADY_LOCKED))
@@ -1090,6 +1584,7 @@ js_GC(JSContext *cx, uintN gcflags)
         return;
     }
     METER(rt->gcStats.poke++);
+    rt->gcPoke = JS_FALSE;
 
 #ifdef JS_THREADSAFE
     /* Bump gcLevel and return rather than nest on this thread. */
@@ -1197,7 +1692,7 @@ js_GC(JSContext *cx, uintN gcflags)
     /* Drop atoms held by the property cache, and clear property weak links. */
     js_DisablePropertyCache(cx);
     js_FlushPropertyCache(cx);
-#ifdef DEBUG_brendan
+#ifdef DEBUG_notme
   { extern void js_DumpScopeMeters(JSRuntime *rt);
     js_DumpScopeMeters(rt);
   }
@@ -1213,7 +1708,10 @@ restart:
     if (rt->gcLocksHash)
         JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_marker, cx);
     js_MarkAtomState(&rt->atomState, gcflags, gc_mark_atom_key_thing, cx);
-    js_MarkWatchPoints(rt);
+    js_MarkWatchPoints(cx);
+    js_MarkScriptFilenames(rt, gcflags);
+    js_MarkNativeIteratorStates(cx);
+
     iter = NULL;
     while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {
         /*
@@ -1256,8 +1754,11 @@ restart:
                 GC_MARK(cx, fp->thisp, "this", NULL);
                 if (fp->argv) {
                     nslots = fp->argc;
-                    if (fp->fun && fp->fun->nargs > nslots)
-                        nslots = fp->fun->nargs;
+                    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))
@@ -1267,6 +1768,9 @@ restart:
                 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);
         }
 
@@ -1276,15 +1780,15 @@ restart:
 
         /* Mark other roots-by-definition in acx. */
         GC_MARK(cx, acx->globalObject, "global object", NULL);
-        GC_MARK(cx, acx->newborn[GCX_OBJECT], "newborn object", NULL);
-        GC_MARK(cx, acx->newborn[GCX_STRING], "newborn string", NULL);
-        GC_MARK(cx, acx->newborn[GCX_DOUBLE], "newborn double", NULL);
-        GC_MARK(cx, acx->newborn[GCX_MUTABLE_STRING], "newborn mutable string",
-                NULL);
-        for (i = GCX_EXTERNAL_STRING; i < GCX_NTYPES; i++)
-            GC_MARK(cx, acx->newborn[i], "newborn external string", NULL);
+        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);
@@ -1302,6 +1806,22 @@ restart:
 
         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);
@@ -1312,114 +1832,142 @@ restart:
 
     /*
      * 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);
-    js_SweepScriptFilenames(rt);
-    for (a = rt->gcArenaPool.first.next; a; a = a->next) {
-        flagp = (uint8 *) a->base;
-        split = (uint8 *) FIRST_THING_PAGE(a);
-        limit = (JSGCThing *) a->avail;
-        for (thing = (JSGCThing *) split; thing < limit; thing++) {
-            if (((jsuword)thing & GC_PAGE_MASK) == 0) {
-                flagp++;
-                thing++;
-            }
-            flags = *flagp;
-            if (flags & GCF_MARK) {
-                *flagp &= ~GCF_MARK;
-            } else if (!(flags & (GCF_LOCKMASK | GCF_FINAL))) {
-                /* Call the finalizer with GCF_FINAL ORed into flags. */
-                type = flags & GCF_TYPEMASK;
-                finalizer = gc_finalizers[type];
-                if (finalizer) {
-                    *flagp = (uint8)(flags | GCF_FINAL);
-                    if (type >= GCX_EXTERNAL_STRING)
-                        js_PurgeDeflatedStringCache((JSString *)thing);
-                    finalizer(cx, thing);
+    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;
+                    /* Set flags to GCF_FINAL, signifying that thing is free. */
+                    *flagp = GCF_FINAL;
 
-                JS_ASSERT(rt->gcBytes >= sizeof(JSGCThing) + sizeof(uint8));
-                rt->gcBytes -= sizeof(JSGCThing) + sizeof(uint8);
+                    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;
             }
-            if (++flagp == split)
-                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.
      */
-    ap = &rt->gcArenaPool.first.next;
-    a = *ap;
-    if (!a)
-        goto out;
-    all_clear = JS_TRUE;
-    flp = oflp = &rt->gcFreeList;
-    *flp = NULL;
-    METER(rt->gcStats.freelen = 0);
-
-    do {
-        flagp = (uint8 *) a->base;
-        split = (uint8 *) FIRST_THING_PAGE(a);
-        limit = (JSGCThing *) a->avail;
-        for (thing = (JSGCThing *) split; thing < limit; thing++) {
-            if (((jsuword)thing & GC_PAGE_MASK) == 0) {
-                flagp++;
-                thing++;
+    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 (*flagp != GCF_FINAL) {
-                all_clear = JS_FALSE;
+
+            if (all_clear) {
+                JS_ARENA_DESTROY(&rt->gcArenaPool[i], a, ap);
+                flp = oflp;
+                METER(rt->gcStats.afree++);
             } else {
-                thing->flagp = flagp;
-                *flp = thing;
-                flp = &thing->next;
-                METER(rt->gcStats.freelen++);
+                ap = &a->next;
+                all_clear = JS_TRUE;
+                oflp = flp;
             }
-            if (++flagp == split)
-                flagp += GC_THINGS_SIZE;
-        }
+        } while ((a = *ap) != NULL);
 
-        if (all_clear) {
-            JS_ARENA_DESTROY(&rt->gcArenaPool, a, ap);
-            flp = oflp;
-            METER(rt->gcStats.afree++);
-        } else {
-            ap = &a->next;
-            all_clear = JS_TRUE;
-            oflp = flp;
-        }
-    } while ((a = *ap) != NULL);
-
-    /* Terminate the new freelist. */
-    *flp = NULL;
+        /* Terminate the new freelist. */
+        *flp = NULL;
+    }
 
     if (rt->gcCallback)
         (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
-#ifdef DEBUG_brendan
+#ifdef DEBUG_notme
   { extern void DumpSrcNoteSizeHist();
     DumpSrcNoteSizeHist();
+    printf("GC HEAP SIZE %lu (%lu)\n",
+           (unsigned long)rt->gcBytes, (unsigned long)rt->gcPrivateBytes);
   }
 #endif
 
-out:
     JS_LOCK_GC(rt);
-    if (rt->gcLevel > 1) {
+    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->gcPoke = rt->gcRunning = JS_FALSE;
+    rt->gcRunning = JS_FALSE;
 
 #ifdef JS_THREADSAFE
     /* If we were invoked during a request, pay back the temporary debit. */
index a4813d16d57082d3173b9b54c8f8eba079682f25..efc13194ee1e9521e0704652c3269410fdf4f9e4 100644 (file)
@@ -54,16 +54,21 @@ JS_BEGIN_EXTERN_C
 #define GCX_DOUBLE              2               /* jsdouble */
 #define GCX_MUTABLE_STRING      3               /* JSString that's mutable --
                                                    single-threaded only! */
-#define GCX_EXTERNAL_STRING     4               /* JSString w/ external chars */
-#define GCX_NTYPES_LOG2         3               /* type index bits */
+#define GCX_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_LOCKSHIFT   (GCX_NTYPES_LOG2 + 2)   /* lock bit shift and mask */
-#define GCF_LOCKMASK    (JS_BITMASK(8 - GCF_LOCKSHIFT) << GCF_LOCKSHIFT)
+#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. */
@@ -119,8 +124,21 @@ 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_AllocGCThing(JSContext *cx, uintN flags);
+js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes);
 
 extern JSBool
 js_LockGCThing(JSContext *cx, void *thing);
@@ -131,7 +149,7 @@ js_LockGCThingRT(JSRuntime *rt, void *thing);
 extern JSBool
 js_UnlockGCThingRT(JSRuntime *rt, void *thing);
 
-extern JSBool 
+extern JSBool
 js_IsAboutToBeFinalized(JSContext *cx, void *thing);
 
 extern void
@@ -169,6 +187,9 @@ struct GCMarkNode {
         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)
@@ -179,7 +200,7 @@ struct GCMarkNode {
  * Flags to modify how a GC marks and sweeps:
  *   GC_KEEP_ATOMS      Don't sweep unmarked atoms, they may be in use by the
  *                      compiler, or by an API function that calls js_Atomize,
- *                      when the GC is called from js_AllocGCThing, due to a
+ *                      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
@@ -197,21 +218,34 @@ 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;    /* gcFreeList length */
-    uint32  recycle;    /* number of things recycled through gcFreeList */
+    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  stuck;      /* stuck reference counts seen by lock calls */
-    uint32  unstuck;    /* unlock calls that saw a stuck lock count */
-    uint32  depth;      /* mark recursion depth */
-    uint32  maxdepth;   /* maximum mark recursion depth */
+    uint32  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 */
@@ -220,11 +254,19 @@ typedef struct JSGCStats {
     uint32  segslots;   /* total stack segment jsval slots scanned */
 } JSGCStats;
 
-extern void
+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___ */
index 954368450196d3ea03136e807c08903cd1fba635..0f22b5e39c767a5bb38746f2a616e7e1a85db1dc 100644 (file)
@@ -114,7 +114,7 @@ JS_NewHashTable(uint32 n, JSHashFunction keyHash,
 
     ht = (JSHashTable*) allocOps->allocTable(allocPriv, sizeof *ht);
     if (!ht)
-       return NULL;
+        return NULL;
     memset(ht, 0, sizeof *ht);
     ht->shift = JS_HASH_BITS - n;
     n = JS_BIT(n);
@@ -211,7 +211,7 @@ JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep,
         if (!ht->buckets) {
             ht->buckets = oldbuckets;
             return NULL;
-       }
+        }
         memset(ht->buckets, 0, nb);
 #ifdef HASHMETER
         ht->ngrows++;
@@ -237,7 +237,7 @@ JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep,
     /* Make a new key value entry */
     he = ht->allocOps->allocEntry(ht->allocPriv, key);
     if (!he)
-       return NULL;
+        return NULL;
     he->keyHash = keyHash;
     he->key = key;
     he->value = value;
index 6881e07dd22f059de36be9376090717c70e93515..096610cf36c1cf4110bcefbcf4e926250a069183 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
  *
  * ***** END LICENSE BLOCK ***** */
 
-/* build on macs with low memory */
-#if defined(XP_MAC) && defined(MOZ_MAC_LOWMEM)
-#pragma optimization_level 1
-#endif
-
 /*
  * JavaScript bytecode interpreter.
  */
 #include "jsjit.h"
 #endif
 
+#if JS_HAS_XML_SUPPORT
+#include "jsxml.h"
+#endif
+
 #ifdef DEBUG
 #define ASSERT_CACHE_IS_EMPTY(cache)                                          \
     JS_BEGIN_MACRO                                                            \
@@ -143,10 +143,6 @@ prop_iterator_finalize(JSContext *cx, JSObject *obj)
                       &iter_state, NULL);
     }
     js_RemoveRoot(cx->runtime, &obj->slots[JSSLOT_PARENT]);
-
-    /* XXX force the GC to restart so we can collect iteratee, if possible,
-           during the current collector activation */
-    cx->runtime->gcLevel++;
 }
 
 static JSClass prop_iterator_class = {
@@ -277,7 +273,7 @@ static JSClass prop_iterator_class = {
 
 #define VALUE_TO_OBJECT(cx, v, obj)                                           \
     JS_BEGIN_MACRO                                                            \
-        if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) {                          \
+        if (!JSVAL_IS_PRIMITIVE(v)) {                                         \
             obj = JSVAL_TO_OBJECT(v);                                         \
         } else {                                                              \
             SAVE_SP(fp);                                                      \
@@ -289,6 +285,13 @@ static JSClass prop_iterator_class = {
         }                                                                     \
     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)) {                                                   \
@@ -396,6 +399,12 @@ js_AllocStack(JSContext *cx, uintN nslots, void **markp)
         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;
 }
 
@@ -424,126 +433,6 @@ js_FreeStack(JSContext *cx, void *mark)
     JS_ARENA_RELEASE(&cx->stackPool, mark);
 }
 
-/*
- * To economize on slots space in functions, the compiler records arguments and
- * local variables as shared (JSPROP_SHARED) properties with well-known getters
- * and setters: js_{Get,Set}Argument, js_{Get,Set}LocalVariable.  Now, we could
- * record args and vars in lists or hash tables in function-private data, but
- * that means more duplication in code, and more data at runtime in the hash
- * table case due to round-up to powers of two, just to recapitulate the scope
- * machinery in the function object.
- *
- * What's more, for a long time (to the dawn of "Mocha" in 1995), these getters
- * and setters knew how to search active stack frames in a context to find the
- * top activation of the function f, in order to satisfy a get or set of f.a,
- * for argument a, or f.x, for local variable x.  You could use f.a instead of
- * just a in function f(a) { return f.a }, for example, to return the actual
- * parameter.
- *
- * ECMA requires that we give up on this ancient extension, because it is not
- * compatible with the standard as used by real-world scripts.  While Chapter
- * 16 does allow for additional properties to be defined on native objects by
- * a conforming implementation, these magic getters and setters cause f.a's
- * meaning to vary unexpectedly.  Real-world scripts set f.A = 42 to define
- * "class static" (after Java) constants, for example, but if A also names an
- * arg or var in f, the constant is not available while f is active, and any
- * non-constant class-static can't be set while f is active.
- *
- * So, to label arg and var properties in functions without giving them magic
- * abilities to affect active frame stack slots, while keeping the properties
- * shared (slot-less) to save space in the common case (where no assignment
- * sets a function property with the same name as an arg or var), the setters
- * for args and vars must handle two special cases here.
- *
- * XXX functions tend to have few args and vars, so we risk O(n^2) growth here
- * XXX ECMA *really* wants args and vars to be stored in function-private data,
- *     not as function object properties.
- */
-static JSBool
-SetFunctionSlot(JSContext *cx, JSObject *obj, JSPropertyOp setter, jsid id,
-                jsval v)
-{
-    uintN slot;
-    JSObject *origobj;
-    JSScope *scope;
-    JSScopeProperty *sprop;
-    JSString *str;
-    JSBool ok;
-
-    slot = (uintN) JSVAL_TO_INT(id);
-    if (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
-        /*
-         * Given a non-function object obj that has a function object in its
-         * prototype chain, where an argument or local variable property named
-         * by (setter, slot) is being set, override the shared property in the
-         * prototype with an unshared property in obj.  This situation arises
-         * in real-world JS due to .prototype setting and collisions among a
-         * function's "static property" names and arg or var names, believe it
-         * or not.
-         */
-        origobj = obj;
-        do {
-            obj = OBJ_GET_PROTO(cx, obj);
-            if (!obj)
-                return JS_TRUE;
-        } while (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass);
-
-        JS_LOCK_OBJ(cx, obj);
-        scope = OBJ_SCOPE(obj);
-        for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
-            if (sprop->setter == setter) {
-                JS_ASSERT(!JSVAL_IS_INT(sprop->id) &&
-                          ATOM_IS_STRING((JSAtom *)sprop->id) &&
-                          (sprop->flags & SPROP_HAS_SHORTID));
-
-                if ((uintN) sprop->shortid == slot) {
-                    str = ATOM_TO_STRING((JSAtom *)sprop->id);
-                    JS_UNLOCK_SCOPE(cx, scope);
-
-                    return JS_DefineUCProperty(cx, origobj,
-                                               JSSTRING_CHARS(str),
-                                               JSSTRING_LENGTH(str),
-                                               v, NULL, NULL,
-                                               JSPROP_ENUMERATE);
-                }
-            }
-        }
-        JS_UNLOCK_SCOPE(cx, scope);
-        return JS_TRUE;
-    }
-
-    /*
-     * Argument and local variable properties of function objects are shared
-     * by default (JSPROP_SHARED), therefore slot-less.  But if for function
-     * f(a) {}, f.a = 42 is evaluated, f.a should be 42 after the assignment,
-     * whether or not f is active.  So js_SetArgument and js_SetLocalVariable
-     * must be prepared to change an arg or var from shared to unshared status,
-     * allocating a slot in obj to hold v.
-     */
-    ok = JS_TRUE;
-    JS_LOCK_OBJ(cx, obj);
-    scope = OBJ_SCOPE(obj);
-    for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
-        if (sprop->setter == setter && (uintN) sprop->shortid == slot) {
-            if (sprop->attrs & JSPROP_SHARED) {
-                sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,
-                                                    0, ~JSPROP_SHARED,
-                                                    sprop->getter, setter);
-                if (!sprop) {
-                    ok = JS_FALSE;
-                } else {
-                    /* See js_SetProperty, near the bottom. */
-                    GC_POKE(cx, pval);
-                    LOCKED_OBJ_SET_SLOT(obj, sprop->slot, v);
-                }
-            }
-            break;
-        }
-    }
-    JS_UNLOCK_SCOPE(cx, scope);
-    return ok;
-}
-
 JSBool
 js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
@@ -553,7 +442,7 @@ js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 JSBool
 js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
-    return SetFunctionSlot(cx, obj, js_SetArgument, id, *vp);
+    return JS_TRUE;
 }
 
 JSBool
@@ -565,25 +454,12 @@ js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 JSBool
 js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
-    return SetFunctionSlot(cx, obj, js_SetLocalVariable, id, *vp);
+    return JS_TRUE;
 }
 
-/*
- * Compute the 'this' parameter and store it in frame as frame.thisp.
- * Activation objects ("Call" objects not created with "new Call()", i.e.,
- * "Call" objects that have private data) may not be referred to by 'this',
- * as dictated by ECMA.
- *
- * N.B.: fp->argv must be set, fp->argv[-1] the nominal 'this' paramter as
- * a jsval, and fp->argv[-2] must be the callee object reference, usually a
- * function object.  Also, fp->flags must contain JSFRAME_CONSTRUCTING if we
- * are preparing for a constructor call.
- */
-static JSBool
-ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp)
+JSBool
+js_ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp)
 {
-    JSObject *parent;
-
     if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) {
         /* Some objects (e.g., With) delegate 'this' to another object. */
         thisp = OBJ_THIS_OBJECT(cx, thisp);
@@ -612,13 +488,25 @@ ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp)
          */
         JS_ASSERT(!(fp->flags & JSFRAME_CONSTRUCTING));
         if (JSVAL_IS_PRIMITIVE(fp->argv[-2]) ||
-            !(parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2])))) {
+            !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2]))) {
             thisp = cx->globalObject;
         } else {
-            /* walk up to find the top-level object */
-            thisp = parent;
-            while ((parent = OBJ_GET_PARENT(cx, thisp)) != NULL)
-                thisp = parent;
+            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;
@@ -977,8 +865,7 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
     JSNative native;
     JSFunction *fun;
     JSScript *script;
-    uintN minargs, nvars;
-    intN nslots, nalloc, surplus;
+    uintN nslots, nvars, nalloc, surplus;
     JSInterpreterHook hook;
     void *hookData;
 
@@ -1013,6 +900,7 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
      */
     if (JSVAL_IS_PRIMITIVE(v)) {
 #if JS_HAS_NO_SUCH_METHOD
+        jsid id;
         jsbytecode *pc;
         jsatomid atomIndex;
         JSAtom *atom;
@@ -1036,14 +924,25 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
          * any such defaulting of |this| to callee (v, *vp) ancestor.
          */
         frame.argv = vp + 2;
-        ok = ComputeThis(cx, thisp, &frame);
+        ok = js_ComputeThis(cx, thisp, &frame);
         if (!ok)
             goto out2;
         thisp = frame.thisp;
 
-        ok = OBJ_GET_PROPERTY(cx, thisp,
-                              (jsid)cx->runtime->atomState.noSuchMethodAtom,
-                              &v);
+        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))
@@ -1053,6 +952,9 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
         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);
@@ -1122,7 +1024,7 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
          * We attempt the conversion under all circumstances for 1.2, but
          * only if there is a call op defined otherwise.
          */
-        if (cx->version == JSVERSION_1_2 ||
+        if (JS_VERSION_IS_1_2(cx) ||
             ((ops == &js_ObjectOps) ? clasp->call : ops->call)) {
             ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);
             if (!ok)
@@ -1138,7 +1040,7 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
         }
         fun = NULL;
         script = NULL;
-        minargs = nvars = 0;
+        nslots = nvars = 0;
 
         /* Try a call or construct native object op. */
         native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call;
@@ -1155,7 +1057,8 @@ have_fun:
             native = fun->u.native;
             script = NULL;
         }
-        minargs = fun->nargs + fun->extra;
+        nslots = (fun->nargs > argc) ? fun->nargs - argc : 0;
+        nslots += fun->extra;
         nvars = fun->nvars;
 
         /* Handle bound method special case. */
@@ -1180,9 +1083,10 @@ have_fun:
     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 = ComputeThis(cx, thisp, &frame);
+    ok = js_ComputeThis(cx, thisp, &frame);
     if (!ok)
         goto out2;
 
@@ -1193,8 +1097,7 @@ have_fun:
     hook = cx->runtime->callHook;
     hookData = NULL;
 
-    /* Check for missing arguments expected by the function. */
-    nslots = (intN)((argc < minargs) ? minargs - argc : 0);
+    /* Check for argument slots required by the function. */
     if (nslots) {
         /* All arguments must be contiguous, so we may have to copy actuals. */
         nalloc = nslots;
@@ -1204,15 +1107,15 @@ have_fun:
             nalloc += 2 + argc;
         } else {
             /* Take advantage of surplus slots in the caller's frame depth. */
+            JS_ASSERT((jsval *)mark >= sp);
             surplus = (jsval *)mark - sp;
-            JS_ASSERT(surplus >= 0);
             nalloc -= surplus;
         }
 
         /* Check whether we have enough space in the caller's frame. */
-        if (nalloc > 0) {
+        if ((intN)nalloc > 0) {
             /* Need space for actuals plus missing formals minus surplus. */
-            newsp = js_AllocRawStack(cx, (uintN)nalloc, NULL);
+            newsp = js_AllocRawStack(cx, nalloc, NULL);
             if (!newsp) {
                 ok = JS_FALSE;
                 goto out;
@@ -1221,7 +1124,7 @@ have_fun:
             /* If we couldn't allocate contiguous args, copy actuals now. */
             if (newsp != mark) {
                 JS_ASSERT(sp + nslots > limit);
-                JS_ASSERT(2 + argc + nslots == (uintN)nalloc);
+                JS_ASSERT(2 + argc + nslots == nalloc);
                 *newsp++ = vp[0];
                 *newsp++ = vp[1];
                 if (argc)
@@ -1235,16 +1138,18 @@ have_fun:
         frame.vars += nslots;
 
         /* Push void to initialize missing args. */
-        while (--nslots >= 0)
+        do {
             PUSH(JSVAL_VOID);
+        } while (--nslots != 0);
     }
+    JS_ASSERT(nslots == 0);
 
     /* Now allocate stack space for local variables. */
-    nslots = (intN)frame.nvars;
-    if (nslots) {
-        surplus = (intN)((jsval *)cx->stackPool.current->avail - frame.vars);
-        if (surplus < nslots) {
-            newsp = js_AllocRawStack(cx, (uintN)nslots, NULL);
+    if (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;
@@ -1256,9 +1161,11 @@ have_fun:
         }
 
         /* Push void to initialize local variables. */
-        while (--nslots >= 0)
+        do {
             PUSH(JSVAL_VOID);
+        } while (--nvars != 0);
     }
+    JS_ASSERT(nvars == 0);
 
     /* Store the current sp in frame before calling fun. */
     SAVE_SP(&frame);
@@ -1297,7 +1204,7 @@ have_fun:
             frame.scopeChain = funobj;
 #endif
         }
-        ok = js_Interpret(cx, &v);
+        ok = js_Interpret(cx, script->code, &v);
     } else {
         /* fun might be onerror trying to report a syntax error in itself. */
         frame.scopeChain = NULL;
@@ -1373,11 +1280,27 @@ js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
     PUSH(OBJECT_TO_JSVAL(obj));
     for (i = 0; i < argc; i++)
         PUSH(argv[i]);
-    fp->sp = sp;
+    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);
@@ -1478,6 +1401,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
     frame.sharpDepth = 0;
     frame.flags = flags;
     frame.dormantNext = NULL;
+    frame.xmlNamespace = NULL;
 
     /*
      * Here we wrap the call to js_Interpret with code to (conditionally)
@@ -1506,7 +1430,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
      * Use frame.rval, not result, so the last result stays rooted across any
      * GC activations nested within this js_Interpret.
      */
-    ok = js_Interpret(cx, &frame.rval);
+    ok = js_Interpret(cx, script->code, &frame.rval);
     *result = frame.rval;
 
     if (hookData) {
@@ -1621,7 +1545,9 @@ ImportProperty(JSContext *cx, JSObject *obj, jsid id)
             ok = OBJ_SET_PROPERTY(cx, target, id, &value);
         } else {
             ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
-                                     attrs & ~JSPROP_EXPORTED,
+                                     attrs & ~(JSPROP_EXPORTED |
+                                               JSPROP_GETTER |
+                                               JSPROP_SETTER),
                                      NULL);
         }
         if (prop)
@@ -1697,7 +1623,7 @@ js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
            : isFunction
            ? js_function_str
            : js_var_str;
-    name = js_AtomToPrintableString(cx, (JSAtom *)id);
+    name = js_AtomToPrintableString(cx, JSID_TO_ATOM(id));
     if (!name)
         goto bad;
     return JS_ReportErrorFlagsAndNumber(cx, report,
@@ -1714,6 +1640,80 @@ bad:
     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
@@ -1725,7 +1725,7 @@ bad:
 #define MAX_INLINE_CALL_COUNT 1000
 
 JSBool
-js_Interpret(JSContext *cx, jsval *result)
+js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
 {
     JSRuntime *rt;
     JSStackFrame *fp;
@@ -1739,9 +1739,10 @@ js_Interpret(JSContext *cx, jsval *result)
     jsint depth, len;
     jsval *sp, *newsp;
     void *mark;
-    jsbytecode *pc, *pc2, *endpc;
+    jsbytecode *endpc, *pc2;
     JSOp op, op2;
     const JSCodeSpec *cs;
+    jsatomid atomIndex;
     JSAtom *atom;
     uintN argc, slot, attrs;
     jsval *vp, lval, rval, ltmp, rtmp;
@@ -1768,6 +1769,9 @@ js_Interpret(JSContext *cx, jsval *result)
 #endif
 #if JS_HAS_GETTER_SETTER
     JSPropertyOp getter, setter;
+#endif
+#if JS_HAS_XML_SUPPORT
+    JSBool foreach = JS_FALSE;
 #endif
     int stackDummy;
 
@@ -1784,7 +1788,7 @@ js_Interpret(JSContext *cx, jsval *result)
     /*
      * Optimized Get and SetVersion for proper script language versioning.
      *
-     * If any native method or JSClass/JSObjectOps hook calls JS_SetVersion
+     * 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
@@ -1793,7 +1797,7 @@ js_Interpret(JSContext *cx, jsval *result)
     currentVersion = script->version;
     originalVersion = cx->version;
     if (currentVersion != originalVersion)
-        JS_SetVersion(cx, currentVersion);
+        js_SetVersion(cx, currentVersion);
 
     /*
      * Prepare to call a user-supplied branch handler, and abort the script
@@ -1824,31 +1828,37 @@ js_Interpret(JSContext *cx, jsval *result)
 
     LOAD_INTERRUPT_HANDLER(rt);
 
-    pc = script->code;
-    endpc = pc + script->length;
-    depth = (jsint) script->depth;
-    len = -1;
-
     /* Check for too much js_Interpret nesting, or too deep a C stack. */
     if (++cx->interpLevel == MAX_INTERP_LEVEL ||
         !JS_CHECK_STACK_SIZE(cx, stackDummy)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
         ok = JS_FALSE;
-        goto out;
+        goto out2;
     }
 
     /*
-     * Allocate operand and pc stack slots for the script's worst-case depth.
+     * 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.
      */
-    newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
-    if (!newsp) {
-        ok = JS_FALSE;
-        goto out;
+    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;
     }
-    sp = newsp + depth;
-    fp->spbase = sp;
-    SAVE_SP(fp);
 
+    endpc = script->code + script->length;
     while (pc < endpc) {
         fp->pc = pc;
         op = (JSOp) *pc;
@@ -1870,7 +1880,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 SAVE_SP(fp);
                 for (n = -nuses; n < 0; n++) {
                     str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
-                    if (str != NULL) {
+                    if (str) {
                         fprintf(tracefp, "%s %s",
                                 (n == -nuses) ? "  inputs:" : ",",
                                 JS_GetStringBytes(str));
@@ -1910,7 +1920,6 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
           case JSOP_GROUP:
-            obj = NULL;
             break;
 
           case JSOP_PUSH:
@@ -1940,11 +1949,13 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
           case JSOP_ENTERWITH:
-            rval = FETCH_OPND(-1);
-            VALUE_TO_OBJECT(cx, rval, obj);
-            withobj = js_NewObject(cx, &js_WithClass, obj, fp->scopeChain);
+            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;
@@ -1958,6 +1969,7 @@ js_Interpret(JSContext *cx, jsval *result)
             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:
@@ -1983,6 +1995,17 @@ js_Interpret(JSContext *cx, jsval *result)
                         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);
@@ -1992,7 +2015,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 if (cx->version == currentVersion) {
                     currentVersion = ifp->callerVersion;
                     if (currentVersion != cx->version)
-                        JS_SetVersion(cx, currentVersion);
+                        js_SetVersion(cx, currentVersion);
                 }
 
                 /* Store the return value in the caller's operand frame. */
@@ -2114,38 +2137,40 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
           case JSOP_TOOBJECT:
-            SAVE_SP(fp);
-            ok = js_ValueToObject(cx, FETCH_OPND(-1), &obj);
-            if (!ok)
-                goto out;
+            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                                                            \
-        /* If the index is not a jsint, atomize it. */                        \
-        id = (jsid) FETCH_OPND(n);                                            \
-        if (JSVAL_IS_INT(id)) {                                               \
-            atom = NULL;                                                      \
+        jsval idval_ = FETCH_OPND(n);                                         \
+        if (JSVAL_IS_INT(idval_)) {                                           \
+            id = INT_JSVAL_TO_JSID(idval_);                                   \
         } else {                                                              \
             SAVE_SP(fp);                                                      \
-            atom = js_ValueToStringAtom(cx, (jsval)id);                       \
-            if (!atom) {                                                      \
-                ok = JS_FALSE;                                                \
+            ok = InternNonIntElementId(cx, idval_, &id);                      \
+            if (!ok)                                                          \
                 goto out;                                                     \
-            }                                                                 \
-            id = (jsid)atom;                                                  \
         }                                                                     \
     JS_END_MACRO
 
-#define POP_ELEMENT_ID(id)                                                    \
-    JS_BEGIN_MACRO                                                            \
-        FETCH_ELEMENT_ID(-1, id);                                             \
-        sp--;                                                                 \
-    JS_END_MACRO
-
 #if JS_HAS_IN_OPERATOR
           case JSOP_IN:
+            SAVE_SP(fp);
             rval = FETCH_OPND(-1);
             if (JSVAL_IS_PRIMITIVE(rval)) {
                 str = js_DecompileValueGenerator(cx, -1, rval, NULL);
@@ -2157,12 +2182,13 @@ js_Interpret(JSContext *cx, jsval *result)
                 ok = JS_FALSE;
                 goto out;
             }
-            sp--;
             obj = JSVAL_TO_OBJECT(rval);
-            FETCH_ELEMENT_ID(-1, id);
+            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);
@@ -2176,13 +2202,13 @@ js_Interpret(JSContext *cx, jsval *result)
              */
             lval = FETCH_OPND(-1);
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
             i = -2;
             goto do_forinloop;
 
           case JSOP_FORNAME:
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
 
             /*
              * ECMA 12.6.3 says to eval the LHS after looking for properties
@@ -2248,14 +2274,31 @@ js_Interpret(JSContext *cx, jsval *result)
             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 */
-                propobj = js_NewObject(cx, &prop_iterator_class, NULL, obj);
+                /*
+                 * 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;
 
                 /*
@@ -2275,20 +2318,27 @@ js_Interpret(JSContext *cx, jsval *result)
                  */
                 *vp = OBJECT_TO_JSVAL(propobj);
 
-                ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);
+                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.
-                 * We do this before checking 'ok' to ensure that propobj is
-                 * in a valid state even if OBJ_ENUMERATE returned JS_FALSE.
                  * NB: This code knows that the first slots are pre-allocated.
                  */
 #if JS_INITIAL_NSLOTS < 5
 #error JS_INITIAL_NSLOTS must be greater than or equal to 5.
 #endif
                 propobj->slots[JSSLOT_ITER_STATE] = iter_state;
-                if (!ok)
-                    goto out;
             } else {
                 /* This is not the first iteration. Recover iterator state. */
                 propobj = JSVAL_TO_OBJECT(rval);
@@ -2298,8 +2348,19 @@ js_Interpret(JSContext *cx, jsval *result)
             }
 
           enum_next_property:
-            /* Get the next jsid to be enumerated and store it in rval. */
-            OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &rval);
+          {
+            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? */
@@ -2309,10 +2370,22 @@ js_Interpret(JSContext *cx, jsval *result)
                 if (!obj) {
                     /* End of property list -- terminate loop. */
                     rval = JSVAL_FALSE;
+#if JS_HAS_XML_SUPPORT
+                    foreach = JS_FALSE;
+#endif
                     goto end_forinloop;
                 }
 
-                ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);
+                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.
@@ -2333,29 +2406,76 @@ js_Interpret(JSContext *cx, jsval *result)
                 goto enum_next_property;
             }
 
-            /* Skip properties not owned by obj, and leave next id in rval. */
-            ok = OBJ_LOOKUP_PROPERTY(cx, origobj, rval, &obj2, &prop);
+            /* 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) {
+            if (prop)
                 OBJ_DROP_PROPERTY(cx, obj2, prop);
 
-                /* Yes, don't enumerate again.  Go to the next property. */
-                if (obj2 != obj)
+            /*
+             * 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;
             }
 
-            /* Make sure rval is a string for uniformity and compatibility. */
-            if (!JSVAL_IS_INT(rval)) {
-                rval = ATOM_KEY((JSAtom *)rval);
-            } else if (cx->version != JSVERSION_1_2) {
-                str = js_NumberToString(cx, (jsdouble) JSVAL_TO_INT(rval));
-                if (!str) {
-                    ok = JS_FALSE;
-                    goto out;
+#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);
+                    rval = STRING_TO_JSVAL(str);
+                } else {
+                    rval = INT_JSID_TO_JSVAL(fid);
+                }
             }
 
             switch (op) {
@@ -2379,6 +2499,8 @@ js_Interpret(JSContext *cx, jsval *result)
               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;
@@ -2396,6 +2518,7 @@ js_Interpret(JSContext *cx, jsval *result)
             sp += i + 1;
             PUSH_OPND(rval);
             break;
+          }
 
           case JSOP_DUP:
             JS_ASSERT(sp > fp->spbase);
@@ -2413,9 +2536,8 @@ js_Interpret(JSContext *cx, jsval *result)
 
 #define PROPERTY_OP(n, call)                                                  \
     JS_BEGIN_MACRO                                                            \
-        /* Pop the left part and resolve it to a non-null object. */          \
-        lval = FETCH_OPND(n);                                                 \
-        VALUE_TO_OBJECT(cx, lval, obj);                                       \
+        /* 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);                                                          \
@@ -2426,16 +2548,31 @@ js_Interpret(JSContext *cx, jsval *result)
 
 #define ELEMENT_OP(n, call)                                                   \
     JS_BEGIN_MACRO                                                            \
+        /* Fetch the right part and resolve it to an internal id. */          \
         FETCH_ELEMENT_ID(n, id);                                              \
-        PROPERTY_OP(n-1, call);                                               \
+                                                                              \
+        /* 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.
+ * 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)                                                      \
+#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;                                                        \
@@ -2445,14 +2582,14 @@ js_Interpret(JSContext *cx, jsval *result)
             if (sprop) {                                                      \
                 JSScope *scope_ = OBJ_SCOPE(obj);                             \
                 slot = (uintN)sprop->slot;                                    \
-                rval = (slot != SPROP_INVALID_SLOT)                           \
-                       ? LOCKED_OBJ_GET_SLOT(obj, slot)                       \
-                       : JSVAL_VOID;                                          \
+                *(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, &rval);                   \
+                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, rval);                     \
+                    LOCKED_OBJ_SET_SLOT(obj, slot, *(vp));                    \
                 JS_UNLOCK_SCOPE(cx, scope_);                                  \
             } else {                                                          \
                 JS_UNLOCK_OBJ(cx, obj);                                       \
@@ -2489,33 +2626,42 @@ js_Interpret(JSContext *cx, jsval *result)
         }                                                                     \
     JS_END_MACRO
 
-          case JSOP_SETCONST:
+#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;
-            atom = GET_ATOM(cx, script, pc);
             rval = FETCH_OPND(-1);
-            ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, rval, NULL, NULL,
+            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);
-            break;
+          END_LITOPX_CASE
 
-          case JSOP_BINDNAME:
-            atom = GET_ATOM(cx, script, pc);
+          BEGIN_LITOPX_CASE(JSOP_BINDNAME, 0)
             SAVE_SP(fp);
-            obj = js_FindIdentifierBase(cx, (jsid)atom);
+            obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom));
             if (!obj) {
                 ok = JS_FALSE;
                 goto out;
             }
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
-            break;
+          END_LITOPX_CASE
 
           case JSOP_SETNAME:
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
             rval = FETCH_OPND(-1);
             lval = FETCH_OPND(-2);
             JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
@@ -2526,6 +2672,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 goto out;
             sp--;
             STORE_OPND(-1, rval);
+            obj = NULL;
             break;
 
 #define INTEGER_OP(OP, EXTRA_CODE)                                            \
@@ -2555,15 +2702,6 @@ js_Interpret(JSContext *cx, jsval *result)
             BITWISE_OP(&);
             break;
 
-#if defined(XP_WIN)
-#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN)                                \
-    ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL))                         \
-     ? (IFNAN)                                                                \
-     : (LVAL) OP (RVAL))
-#else
-#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))
-#endif
-
 #define RELATIONAL_OP(OP)                                                     \
     JS_BEGIN_MACRO                                                            \
         rval = FETCH_OPND(-1);                                                \
@@ -2577,10 +2715,11 @@ js_Interpret(JSContext *cx, jsval *result)
             } else {                                                          \
                 d  = ltmp ? JSVAL_TO_INT(lval) : *rt->jsNaN;                  \
                 d2 = rtmp ? JSVAL_TO_INT(rval) : *rt->jsNaN;                  \
-                cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE);                  \
+                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);                                 \
@@ -2589,19 +2728,63 @@ js_Interpret(JSContext *cx, jsval *result)
             } else {                                                          \
                 VALUE_TO_NUMBER(cx, lval, d);                                 \
                 VALUE_TO_NUMBER(cx, rval, d2);                                \
-                cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE);                  \
+                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);                                 \
@@ -2610,8 +2793,9 @@ js_Interpret(JSContext *cx, jsval *result)
             } else if (ltmp == JSVAL_DOUBLE) {                                \
                 d  = *JSVAL_TO_DOUBLE(lval);                                  \
                 d2 = *JSVAL_TO_DOUBLE(rval);                                  \
-                cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                     \
+                cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                    \
             } else {                                                          \
+                XML_NAME_EQUALITY_OP(OP)                                      \
                 /* Handle all undefined (=>NaN) and int combinations. */      \
                 cond = lval OP rval;                                          \
             }                                                                 \
@@ -2622,10 +2806,12 @@ js_Interpret(JSContext *cx, jsval *result)
                 cond = 1 OP 0;                                                \
             } else {                                                          \
                 if (ltmp == JSVAL_OBJECT) {                                   \
-                    VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &lval);         \
+                    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, &rval);         \
+                    VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &sp[-1]);       \
+                    rval = sp[-1];                                            \
                     rtmp = JSVAL_TAG(rval);                                   \
                 }                                                             \
                 if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) {           \
@@ -2635,7 +2821,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 } else {                                                      \
                     VALUE_TO_NUMBER(cx, lval, d);                             \
                     VALUE_TO_NUMBER(cx, rval, d2);                            \
-                    cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                 \
+                    cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                \
                 }                                                             \
             }                                                                 \
         }                                                                     \
@@ -2652,52 +2838,26 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
 #if !JS_BUG_FALLIBLE_EQOPS
-#define NEW_EQUALITY_OP(OP, IFNAN)                                            \
+#define NEW_EQUALITY_OP(OP)                                                   \
     JS_BEGIN_MACRO                                                            \
         rval = FETCH_OPND(-1);                                                \
         lval = FETCH_OPND(-2);                                                \
-        ltmp = JSVAL_TAG(lval);                                               \
-        rtmp = JSVAL_TAG(rval);                                               \
-        if (ltmp == rtmp) {                                                   \
-            if (ltmp == JSVAL_STRING) {                                       \
-                str  = JSVAL_TO_STRING(lval);                                 \
-                str2 = JSVAL_TO_STRING(rval);                                 \
-                cond = js_CompareStrings(str, str2) OP 0;                     \
-            } else if (ltmp == JSVAL_DOUBLE) {                                \
-                d  = *JSVAL_TO_DOUBLE(lval);                                  \
-                d2 = *JSVAL_TO_DOUBLE(rval);                                  \
-                cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                     \
-            } else {                                                          \
-                cond = lval OP rval;                                          \
-            }                                                                 \
-        } else {                                                              \
-            if (ltmp == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) {                 \
-                d  = *JSVAL_TO_DOUBLE(lval);                                  \
-                d2 = JSVAL_TO_INT(rval);                                      \
-                cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                     \
-            } else if (JSVAL_IS_INT(lval) && rtmp == JSVAL_DOUBLE) {          \
-                d  = JSVAL_TO_INT(lval);                                      \
-                d2 = *JSVAL_TO_DOUBLE(rval);                                  \
-                cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                     \
-            } else {                                                          \
-                cond = lval OP rval;                                          \
-            }                                                                 \
-        }                                                                     \
+        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(==, JS_FALSE);
+            NEW_EQUALITY_OP(==);
             break;
 
           case JSOP_NEW_NE:
-            NEW_EQUALITY_OP(!=, JS_TRUE);
+            NEW_EQUALITY_OP(!=);
             break;
 
 #if JS_HAS_SWITCH_STATEMENT
           case JSOP_CASE:
-            NEW_EQUALITY_OP(==, JS_FALSE);
+            NEW_EQUALITY_OP(==);
             (void) POP();
             if (cond) {
                 len = GET_JUMP_OFFSET(pc);
@@ -2708,7 +2868,7 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
           case JSOP_CASEX:
-            NEW_EQUALITY_OP(==, JS_FALSE);
+            NEW_EQUALITY_OP(==);
             (void) POP();
             if (cond) {
                 len = GET_JUMPX_OFFSET(pc);
@@ -2768,32 +2928,52 @@ js_Interpret(JSContext *cx, jsval *result)
           case JSOP_ADD:
             rval = FETCH_OPND(-1);
             lval = FETCH_OPND(-2);
-            VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &ltmp);
-            VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &rtmp);
-            if ((cond = JSVAL_IS_STRING(ltmp)) || JSVAL_IS_STRING(rtmp)) {
+#if 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);
-                if (cond) {
-                    str = JSVAL_TO_STRING(ltmp);
-                    ok = (str2 = js_ValueToString(cx, rtmp)) != NULL;
-                } else {
-                    str2 = JSVAL_TO_STRING(rtmp);
-                    ok = (str = js_ValueToString(cx, ltmp)) != NULL;
-                }
+                ok = ops->concatenate(cx, obj2, rval, &rval);
                 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);
+                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;
 
@@ -2892,6 +3072,7 @@ js_Interpret(JSContext *cx, jsval *result)
 #if JS_HAS_INITIALIZERS
           do_new:
 #endif
+            SAVE_SP(fp);
             vp = sp - (2 + argc);
             JS_ASSERT(vp >= fp->spbase);
 
@@ -2904,7 +3085,6 @@ js_Interpret(JSContext *cx, jsval *result)
                 OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass ||
                 !obj2->map->ops->construct)
             {
-                SAVE_SP(fp);
                 fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT);
                 if (!fun) {
                     ok = JS_FALSE;
@@ -2917,12 +3097,19 @@ js_Interpret(JSContext *cx, jsval *result)
                 proto = parent = NULL;
                 fun = NULL;
             } else {
-                /* Get the constructor prototype object for this function. */
+                /*
+                 * 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,
-                                      (jsid)rt->atomState.classPrototypeAtom,
-                                      &rval);
+                                      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);
 
@@ -2940,7 +3127,6 @@ js_Interpret(JSContext *cx, jsval *result)
 
             /* Now we have an object with a constructor method; call it. */
             vp[1] = OBJECT_TO_JSVAL(obj);
-            SAVE_SP(fp);
             ok = js_Invoke(cx, argc, JSINVOKE_CONSTRUCT);
             RESTORE_SP(fp);
             LOAD_BRANCH_CALLBACK(cx);
@@ -2953,17 +3139,14 @@ js_Interpret(JSContext *cx, jsval *result)
             /* Check the return value and update obj from it. */
             rval = *vp;
             if (JSVAL_IS_PRIMITIVE(rval)) {
-                if (fun || !JSVERSION_IS_ECMA(cx->version)) {
+                if (fun || !JS_VERSION_IS_ECMA(cx)) {
                     *vp = OBJECT_TO_JSVAL(obj);
                     break;
                 }
                 /* native [[Construct]] returning primitive is error */
-                str = js_ValueToString(cx, rval);
-                if (str) {
-                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                         JSMSG_BAD_NEW_RESULT,
-                                         JS_GetStringBytes(str));
-                }
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                     JSMSG_BAD_NEW_RESULT,
+                                     js_ValueToPrintableString(cx, rval));
                 ok = JS_FALSE;
                 goto out;
             }
@@ -2973,7 +3156,7 @@ js_Interpret(JSContext *cx, jsval *result)
 
           case JSOP_DELNAME:
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
 
             SAVE_SP(fp);
             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
@@ -2993,7 +3176,7 @@ js_Interpret(JSContext *cx, jsval *result)
 
           case JSOP_DELPROP:
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
             PROPERTY_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
             STORE_OPND(-1, rval);
             break;
@@ -3005,11 +3188,11 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
           case JSOP_TYPEOF:
-            rval = POP_OPND();
+            rval = FETCH_OPND(-1);
+            SAVE_SP(fp);
             type = JS_TypeOfValue(cx, rval);
             atom = rt->atomState.typeAtoms[type];
-            str  = ATOM_TO_STRING(atom);
-            PUSH_OPND(STRING_TO_JSVAL(str));
+            STORE_OPND(-1, ATOM_KEY(atom));
             break;
 
           case JSOP_VOID:
@@ -3022,7 +3205,7 @@ js_Interpret(JSContext *cx, jsval *result)
           case JSOP_NAMEINC:
           case JSOP_NAMEDEC:
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
 
             SAVE_SP(fp);
             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
@@ -3033,6 +3216,7 @@ js_Interpret(JSContext *cx, jsval *result)
 
             OBJ_DROP_PROPERTY(cx, obj2, prop);
             lval = OBJECT_TO_JSVAL(obj);
+            i = 0;
             goto do_incop;
 
           case JSOP_INCPROP:
@@ -3040,19 +3224,24 @@ js_Interpret(JSContext *cx, jsval *result)
           case JSOP_PROPINC:
           case JSOP_PROPDEC:
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
-            lval = POP_OPND();
+            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:
-            POP_ELEMENT_ID(id);
-            lval = POP_OPND();
+            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);
@@ -3076,7 +3265,9 @@ js_Interpret(JSContext *cx, jsval *result)
 /*
  * 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.
+ * 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                                                            \
@@ -3087,6 +3278,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 ok = js_NewNumberValue(cx, d, &rtmp);                         \
                 if (!ok)                                                      \
                     goto out;                                                 \
+                *vp = rtmp;                                                   \
             }                                                                 \
             (cs->format & JOF_INC) ? d++ : d--;                               \
             ok = js_NewNumberValue(cx, d, &rval);                             \
@@ -3099,12 +3291,30 @@ js_Interpret(JSContext *cx, jsval *result)
             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;
 
@@ -3187,15 +3397,17 @@ js_Interpret(JSContext *cx, jsval *result)
 #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);
-            PUSH_OPND(rtmp);
+            STORE_OPND(-1, rtmp);
             break;
 
           case JSOP_GETPROP:
             /* Get an immediate atom naming the property. */
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
             PROPERTY_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)));
             STORE_OPND(-1, rval);
             break;
@@ -3206,10 +3418,11 @@ js_Interpret(JSContext *cx, jsval *result)
 
             /* Get an immediate atom naming the property. */
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            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:
@@ -3223,13 +3436,14 @@ js_Interpret(JSContext *cx, jsval *result)
             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);
-            lval = FETCH_OPND(-2);
-            VALUE_TO_OBJECT(cx, lval, obj);
+            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);
@@ -3322,7 +3536,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 newifp->mark = newmark;
 
                 /* Compute the 'this' parameter now that argv is set. */
-                ok = ComputeThis(cx, JSVAL_TO_OBJECT(vp[1]), &newifp->frame);
+                ok = js_ComputeThis(cx, JSVAL_TO_OBJECT(vp[1]), &newifp->frame);
                 if (!ok) {
                     js_FreeRawStack(cx, newmark);
                     goto bad_inline_call;
@@ -3352,7 +3566,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 if (cx->version == currentVersion) {
                     currentVersion = script->version;
                     if (currentVersion != cx->version)
-                        JS_SetVersion(cx, currentVersion);
+                        js_SetVersion(cx, currentVersion);
                 }
 
                 /* Push the frame and set interpreter registers. */
@@ -3426,7 +3640,7 @@ js_Interpret(JSContext *cx, jsval *result)
 
           case JSOP_NAME:
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
 
             SAVE_SP(fp);
             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
@@ -3482,15 +3696,86 @@ js_Interpret(JSContext *cx, jsval *result)
             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:
-            atom = GET_ATOM(cx, script, pc);
+            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;
 
-          case JSOP_REGEXP:
+          BEGIN_LITOPX_CASE(JSOP_REGEXP, 0)
           {
             JSRegExp *re;
             JSObject *funobj;
@@ -3519,7 +3804,6 @@ js_Interpret(JSContext *cx, jsval *result)
              * need a similar op for other kinds of object literals, we should
              * push cloning down under JSObjectOps and reuse code here.
              */
-            atom = GET_ATOM(cx, script, pc);
             JS_ASSERT(ATOM_IS_OBJECT(atom));
             obj = ATOM_TO_OBJECT(atom);
             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
@@ -3558,6 +3842,15 @@ js_Interpret(JSContext *cx, jsval *result)
                 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.
@@ -3602,8 +3895,8 @@ js_Interpret(JSContext *cx, jsval *result)
 
             PUSH_OPND(rval);
             obj = NULL;
-            break;
           }
+          END_LITOPX_CASE
 
           case JSOP_ZERO:
             PUSH_OPND(JSVAL_ZERO);
@@ -3621,7 +3914,22 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
           case JSOP_THIS:
-            PUSH_OPND(OBJECT_TO_JSVAL(fp->thisp));
+            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;
 
@@ -3645,8 +3953,8 @@ js_Interpret(JSContext *cx, jsval *result)
              * the default case if the discriminant isn't already an int jsval.
              * (This opcode is emitted only for dense jsint-domain switches.)
              */
-            if (cx->version == JSVERSION_DEFAULT ||
-                cx->version >= JSVERSION_1_4) {
+            if ((cx->version & JSVERSION_MASK) == JSVERSION_DEFAULT ||
+                (cx->version & JSVERSION_MASK) >= JSVERSION_1_4) {
                 rval = POP_OPND();
                 if (!JSVAL_IS_INT(rval))
                     break;
@@ -3728,8 +4036,8 @@ js_Interpret(JSContext *cx, jsval *result)
              * the default case if the discriminant isn't already an int jsval.
              * (This opcode is emitted only for dense jsint-domain switches.)
              */
-            if (cx->version == JSVERSION_DEFAULT ||
-                cx->version >= JSVERSION_1_4) {
+            if ((cx->version & JSVERSION_MASK) == JSVERSION_DEFAULT ||
+                (cx->version & JSVERSION_MASK) >= JSVERSION_1_4) {
                 rval = POP_OPND();
                 if (!JSVAL_IS_INT(rval))
                     break;
@@ -3809,6 +4117,7 @@ js_Interpret(JSContext *cx, jsval *result)
 
 #if JS_HAS_EXPORT_IMPORT
           case JSOP_EXPORTALL:
+            SAVE_SP(fp);
             obj = fp->varobj;
             ida = JS_Enumerate(cx, obj);
             if (!ida) {
@@ -3834,10 +4143,10 @@ js_Interpret(JSContext *cx, jsval *result)
             }
             break;
 
-          case JSOP_EXPORTNAME:
-            atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+          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;
@@ -3854,10 +4163,10 @@ js_Interpret(JSContext *cx, jsval *result)
             }
             if (!ok)
                 goto out;
-            break;
+          END_LITOPX_CASE
 
           case JSOP_IMPORTALL:
-            id = (jsid)JSVAL_VOID;
+            id = (jsid) JSVAL_VOID;
             PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
             sp--;
             break;
@@ -3865,7 +4174,7 @@ js_Interpret(JSContext *cx, jsval *result)
           case JSOP_IMPORTPROP:
             /* Get an immediate atom naming the property. */
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
             PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
             sp--;
             break;
@@ -3911,7 +4220,7 @@ js_Interpret(JSContext *cx, jsval *result)
             break;
 
           case JSOP_ARGSUB:
-            id = (jsid) INT_TO_JSVAL(GET_ARGNO(pc));
+            id = INT_TO_JSID(GET_ARGNO(pc));
             SAVE_SP(fp);
             ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
             if (!ok)
@@ -3933,7 +4242,7 @@ js_Interpret(JSContext *cx, jsval *result)
 #undef LAZY_ARGS_THISP
 
           case JSOP_ARGCNT:
-            id = (jsid) rt->atomState.lengthAtom;
+            id = ATOM_TO_JSID(rt->atomState.lengthAtom);
             SAVE_SP(fp);
             ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
             if (!ok)
@@ -4000,7 +4309,7 @@ js_Interpret(JSContext *cx, jsval *result)
                  * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
                  */
                 atom = GET_ATOM(cx, script, pc);
-                id = (jsid)atom;
+                id = ATOM_TO_JSID(atom);
                 SAVE_SP(fp);
                 CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
                 if (!ok)
@@ -4011,14 +4320,15 @@ js_Interpret(JSContext *cx, jsval *result)
                 GC_POKE(cx, obj->slots[slot]);
                 OBJ_SET_SLOT(cx, obj, slot, rval);
             }
+            obj = NULL;
             break;
 
           case JSOP_DEFCONST:
           case JSOP_DEFVAR:
-          {
-            jsatomid atomIndex;
-
             atomIndex = GET_ATOM_INDEX(pc);
+
+          do_JSOP_DEFCONST:
+          do_JSOP_DEFVAR:
             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
             obj = fp->varobj;
             attrs = JSPROP_ENUMERATE;
@@ -4028,7 +4338,8 @@ js_Interpret(JSContext *cx, jsval *result)
                 attrs |= JSPROP_READONLY;
 
             /* Lookup id in order to check for redeclaration problems. */
-            id = (jsid)atom;
+            id = ATOM_TO_JSID(atom);
+            SAVE_SP(fp);
             ok = js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop);
             if (!ok)
                 goto out;
@@ -4049,7 +4360,7 @@ js_Interpret(JSContext *cx, jsval *result)
              * and has stub getter and setter, into a "fast global" accessed
              * by the JSOP_*GVAR opcodes.
              */
-            if (script->numGlobalVars &&
+            if (atomIndex < script->numGlobalVars &&
                 (attrs & JSPROP_PERMANENT) &&
                 obj2 == obj &&
                 OBJ_IS_NATIVE(obj)) {
@@ -4069,18 +4380,16 @@ js_Interpret(JSContext *cx, jsval *result)
 
             OBJ_DROP_PROPERTY(cx, obj2, prop);
             break;
-          }
 
-          case JSOP_DEFFUN:
+          BEGIN_LITOPX_CASE(JSOP_DEFFUN, 0)
           {
-            jsatomid atomIndex;
             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 = (jsid) fun->atom;
+            id = ATOM_TO_JSID(fun->atom);
 
             /*
              * We must be at top-level (either outermost block that forms a
@@ -4089,8 +4398,8 @@ js_Interpret(JSContext *cx, jsval *result)
              * in the same compilation unit (ECMA Program).
              *
              * However, we could be in a Program being eval'd from inside a
-             * with statement, so we need to distinguish variables object from
-             * scope chain head.  Hence the two assignments to parent below.
+             * 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.
              *
@@ -4112,15 +4421,23 @@ js_Interpret(JSContext *cx, jsval *result)
              * promote compile-cost sharing and amortizing, and because Script
              * is not and will not be standardized.
              */
-            parent = fp->scopeChain;
-            if (OBJ_GET_PARENT(cx, obj) != parent) {
-                obj = js_CloneFunctionObject(cx, obj, parent);
+            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
@@ -4136,8 +4453,10 @@ js_Interpret(JSContext *cx, jsval *result)
              * in the property itself, not in obj->slots.
              */
             flags = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
-            if (flags)
+            if (flags) {
                 attrs |= flags | JSPROP_SHARED;
+                rval = JSVAL_VOID;
+            }
 
             /*
              * Check for a const property of the same name -- or any kind
@@ -4146,22 +4465,26 @@ js_Interpret(JSContext *cx, jsval *result)
              * as well as multiple HTML script tags.
              */
             parent = fp->varobj;
+            SAVE_SP(fp);
             ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
-            if (!ok)
-                goto out;
+            if (ok) {
+                ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval,
+                                         (flags & JSFUN_GETTER)
+                                         ? (JSPropertyOp) obj
+                                         : NULL,
+                                         (flags & JSFUN_SETTER)
+                                         ? (JSPropertyOp) obj
+                                         : NULL,
+                                         attrs,
+                                         &prop);
+            }
 
-            ok = OBJ_DEFINE_PROPERTY(cx, parent, id,
-                                     flags ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
-                                     (flags & JSFUN_GETTER)
-                                     ? (JSPropertyOp) obj
-                                     : NULL,
-                                     (flags & JSFUN_SETTER)
-                                     ? (JSPropertyOp) obj
-                                     : NULL,
-                                     attrs,
-                                     &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) {
                 /*
@@ -4172,12 +4495,13 @@ js_Interpret(JSContext *cx, jsval *result)
                 sprop = (JSScopeProperty *) prop;
                 fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
             }
+#endif
             OBJ_DROP_PROPERTY(cx, parent, prop);
-            break;
           }
+          END_LITOPX_CASE
 
 #if JS_HAS_LEXICAL_CLOSURE
-          case JSOP_DEFLOCALFUN:
+          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
@@ -4185,15 +4509,14 @@ js_Interpret(JSContext *cx, jsval *result)
              * This is an optimization over JSOP_DEFFUN that avoids requiring
              * a call object for the outer function's activation.
              */
-            pc2 = pc;
-            slot = GET_VARNO(pc2);
-            pc2 += VARNO_LEN;
-            atom = GET_ATOM(cx, script, pc2);
+            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;
@@ -4201,16 +4524,16 @@ js_Interpret(JSContext *cx, jsval *result)
                 }
             }
             fp->vars[slot] = OBJECT_TO_JSVAL(obj);
-            break;
+          END_LITOPX_CASE
 
-          case JSOP_ANONFUNOBJ:
+          BEGIN_LITOPX_CASE(JSOP_ANONFUNOBJ, 0)
             /* Push the specified function object literal. */
-            atom = GET_ATOM(cx, script, pc);
             obj = ATOM_TO_OBJECT(atom);
 
             /* If re-parenting, push a clone of the function object. */
             parent = fp->scopeChain;
             if (OBJ_GET_PARENT(cx, obj) != parent) {
+                SAVE_SP(fp);
                 obj = js_CloneFunctionObject(cx, obj, parent);
                 if (!obj) {
                     ok = JS_FALSE;
@@ -4218,11 +4541,11 @@ js_Interpret(JSContext *cx, jsval *result)
                 }
             }
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
-            break;
+            obj = NULL;
+          END_LITOPX_CASE
 
-          case JSOP_NAMEDFUNOBJ:
+          BEGIN_LITOPX_CASE(JSOP_NAMEDFUNOBJ, 0)
             /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
-            atom = GET_ATOM(cx, script, pc);
             rval = ATOM_KEY(atom);
             JS_ASSERT(JSVAL_IS_FUNCTION(cx, rval));
 
@@ -4235,8 +4558,8 @@ js_Interpret(JSContext *cx, jsval *result)
              * of the Function object clone.
              */
             SAVE_SP(fp);
-            parent = js_ConstructObject(cx, &js_ObjectClass, NULL,
-                                        fp->scopeChain, 0, NULL);
+            obj2 = fp->scopeChain;
+            parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2);
             if (!parent) {
                 ok = JS_FALSE;
                 goto out;
@@ -4247,13 +4570,30 @@ js_Interpret(JSContext *cx, jsval *result)
              * 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],
@@ -4261,10 +4601,11 @@ js_Interpret(JSContext *cx, jsval *result)
              */
             fun = (JSFunction *) JS_GetPrivate(cx, obj);
             attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
-            if (attrs)
+            if (attrs) {
                 attrs |= JSPROP_SHARED;
-            ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom,
-                                     attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
+                rval = JSVAL_VOID;
+            }
+            ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
                                      (attrs & JSFUN_GETTER)
                                      ? (JSPropertyOp) obj
                                      : NULL,
@@ -4275,6 +4616,9 @@ js_Interpret(JSContext *cx, jsval *result)
                                      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;
@@ -4285,12 +4629,10 @@ js_Interpret(JSContext *cx, jsval *result)
              * 6. Return Result(3).
              */
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
-            break;
-
-          case JSOP_CLOSURE:
-          {
-            jsatomid atomIndex;
+            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
@@ -4299,8 +4641,6 @@ js_Interpret(JSContext *cx, jsval *result)
              * Get immediate operand atom, which is a function object literal.
              * From it, get the function to close.
              */
-            atomIndex = GET_ATOM_INDEX(pc);
-            atom = js_GetAtom(cx, &script->atomMap, atomIndex);
             JS_ASSERT(JSVAL_IS_FUNCTION(cx, ATOM_KEY(atom)));
             obj = ATOM_TO_OBJECT(atom);
 
@@ -4311,15 +4651,24 @@ js_Interpret(JSContext *cx, jsval *result)
              * have seen the right parent already and created a sufficiently
              * well-scoped function object.
              */
-            parent = fp->scopeChain;
-            if (OBJ_GET_PARENT(cx, obj) != parent) {
-                obj = js_CloneFunctionObject(cx, obj, parent);
+            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
@@ -4327,11 +4676,12 @@ js_Interpret(JSContext *cx, jsval *result)
              */
             fun = (JSFunction *) JS_GetPrivate(cx, obj);
             attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
-            if (attrs)
+            if (attrs) {
                 attrs |= JSPROP_SHARED;
+                rval = JSVAL_VOID;
+            }
             parent = fp->varobj;
-            ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom,
-                                     attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
+            ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
                                      (attrs & JSFUN_GETTER)
                                      ? (JSPropertyOp) obj
                                      : NULL,
@@ -4341,10 +4691,15 @@ js_Interpret(JSContext *cx, jsval *result)
                                      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
@@ -4354,9 +4709,9 @@ js_Interpret(JSContext *cx, jsval *result)
                 sprop = (JSScopeProperty *) prop;
                 fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
             }
+#endif
             OBJ_DROP_PROPERTY(cx, parent, prop);
-            break;
-          }
+          END_LITOPX_CASE
 #endif /* JS_HAS_LEXICAL_CLOSURE */
 
 #if JS_HAS_GETTER_SETTER
@@ -4370,34 +4725,33 @@ js_Interpret(JSContext *cx, jsval *result)
               case JSOP_SETNAME:
               case JSOP_SETPROP:
                 atom = GET_ATOM(cx, script, pc);
-                id   = (jsid)atom;
+                id   = ATOM_TO_JSID(atom);
+                rval = FETCH_OPND(-1);
                 i = -1;
-                rval = FETCH_OPND(i);
                 goto gs_pop_lval;
 
               case JSOP_SETELEM:
                 rval = FETCH_OPND(-1);
+                FETCH_ELEMENT_ID(-2, id);
                 i = -2;
-                FETCH_ELEMENT_ID(i, id);
               gs_pop_lval:
-                lval = FETCH_OPND(i-1);
-                VALUE_TO_OBJECT(cx, lval, obj);
+                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;
-                rval = FETCH_OPND(i);
                 atom = GET_ATOM(cx, script, pc);
-                id   = (jsid)atom;
+                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;
-                FETCH_ELEMENT_ID(i, id);
               gs_get_lval:
                 lval = FETCH_OPND(i-1);
                 JS_ASSERT(JSVAL_IS_OBJECT(lval));
@@ -4409,6 +4763,10 @@ js_Interpret(JSContext *cx, jsval *result)
                 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,
@@ -4448,6 +4806,7 @@ js_Interpret(JSContext *cx, jsval *result)
             if (!ok)
                 goto out;
 
+            obj = NULL;
             sp += i;
             if (cs->ndefs)
                 STORE_OPND(-1, rval);
@@ -4478,7 +4837,7 @@ js_Interpret(JSContext *cx, jsval *result)
 
             /* Get the immediate property name into id. */
             atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
             i = -1;
             goto do_init;
 
@@ -4497,7 +4856,11 @@ js_Interpret(JSContext *cx, jsval *result)
             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;
@@ -4506,6 +4869,7 @@ js_Interpret(JSContext *cx, jsval *result)
 
 #if JS_HAS_SHARP_VARS
           case JSOP_DEFSHARP:
+            SAVE_SP(fp);
             obj = fp->sharpArray;
             if (!obj) {
                 obj = js_NewArrayObject(cx, 0, NULL);
@@ -4516,7 +4880,7 @@ js_Interpret(JSContext *cx, jsval *result)
                 fp->sharpArray = obj;
             }
             i = (jsint) GET_ATOM_INDEX(pc);
-            id = (jsid) INT_TO_JSVAL(i);
+            id = INT_TO_JSID(i);
             rval = FETCH_OPND(-1);
             if (JSVAL_IS_PRIMITIVE(rval)) {
                 char numBuf[12];
@@ -4533,11 +4897,12 @@ js_Interpret(JSContext *cx, jsval *result)
 
           case JSOP_USESHARP:
             i = (jsint) GET_ATOM_INDEX(pc);
-            id = (jsid) INT_TO_JSVAL(i);
+            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;
@@ -4566,15 +4931,34 @@ js_Interpret(JSContext *cx, jsval *result)
             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));
@@ -4583,6 +4967,19 @@ js_Interpret(JSContext *cx, jsval *result)
           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;
@@ -4590,6 +4987,12 @@ js_Interpret(JSContext *cx, jsval *result)
 
           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:
@@ -4599,32 +5002,48 @@ js_Interpret(JSContext *cx, jsval *result)
             /* let the code at out try to catch the exception. */
             goto out;
 
-          case JSOP_INITCATCHVAR:
-            /* Pop the property's value into rval. */
+          BEGIN_LITOPX_CASE(JSOP_INITCATCHVAR, 0)
+            /* Load the value into rval, while keeping it live on stack. */
             JS_ASSERT(sp - fp->spbase >= 2);
-            rval = POP_OPND();
+            rval = FETCH_OPND(-1);
 
             /* Get the immediate catch variable name into id. */
-            atom = GET_ATOM(cx, script, pc);
-            id   = (jsid)atom;
+            id   = ATOM_TO_JSID(atom);
 
             /* Find the object being initialized at top of stack. */
-            lval = FETCH_OPND(-1);
+            lval = FETCH_OPND(-2);
             JS_ASSERT(JSVAL_IS_OBJECT(lval));
             obj = JSVAL_TO_OBJECT(lval);
 
-            /* Define obj[id] to contain rval and to be permanent. */
-            ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
-                                     JSPROP_PERMANENT, NULL);
+            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;
-            break;
+            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)) {
+            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) {
@@ -4635,15 +5054,12 @@ js_Interpret(JSContext *cx, jsval *result)
                 ok = JS_FALSE;
                 goto out;
             }
-            obj = JSVAL_TO_OBJECT(rval);
             lval = FETCH_OPND(-2);
             cond = JS_FALSE;
-            if (obj->map->ops->hasInstance) {
-                SAVE_SP(fp);
-                ok = obj->map->ops->hasInstance(cx, obj, lval, &cond);
-                if (!ok)
-                    goto out;
-            }
+            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;
@@ -4680,6 +5096,317 @@ js_Interpret(JSContext *cx, jsval *result)
           }
 #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);
@@ -4701,6 +5428,8 @@ js_Interpret(JSContext *cx, jsval *result)
             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) {
@@ -4724,45 +5453,73 @@ js_Interpret(JSContext *cx, jsval *result)
 out:
 
 #if JS_HAS_EXCEPTIONS
-    /*
-     * Has an exception been raised?
-     */
-    if (!ok && cx->throwing) {
+    if (!ok) {
         /*
-         * Call debugger throw hook if set (XXX thread safety?).
+         * 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 {
+         *        <xml/>.(@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
          */
-        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:;
+        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);
             }
-            LOAD_INTERRUPT_HANDLER(rt);
-        }
 
-        /*
-         * Look for a try block within this frame that can catch the exception.
-         */
-        SCRIPT_FIND_CATCH_START(script, pc, pc);
-        if (pc) {
-            len = 0;
-            cx->throwing = JS_FALSE;    /* caught */
-            ok = JS_TRUE;
-            goto advance_pc;
+            /*
+             * 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:;
     }
-no_catch:
 #endif
 
     /*
@@ -4770,19 +5527,29 @@ no_catch:
      * exception thrown under such a function was not caught by it.  If so, go
      * to the inline code under JSOP_RETURN.
      */
-    if (inlineCallCount)
+    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.
      */
-    fp->sp = fp->spbase;
-    fp->spbase = NULL;
-    js_FreeRawStack(cx, mark);
+    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);
+        js_SetVersion(cx, originalVersion);
     cx->interpLevel--;
     return ok;
 
index 81f16d76022f15d570084f2dfff25397cf6f4cc2..edf70f86f3ec1c8b1cc21f0d196ef04f3938d761 100644 (file)
@@ -72,6 +72,7 @@ struct JSStackFrame {
     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 {
@@ -93,7 +94,8 @@ typedef struct JSInlineFrame {
 #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 */ 
+                                       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
@@ -254,9 +256,24 @@ 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).
+ * 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);
@@ -295,7 +312,10 @@ js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
                       JSObject **objp, JSProperty **propp);
 
 extern JSBool
-js_Interpret(JSContext *cx, jsval *result);
+js_StrictlyEqual(jsval lval, jsval rval);
+
+extern JSBool
+js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result);
 
 JS_END_EXTERN_C
 
index 7cbcf767abe6797e72e5831db8fdf79e15c3cb6b..544d8f800b561e595aa98028f092531b0acd036b 100644 (file)
 #define __P(p)  ()
 #endif
 
-#if defined _WIN32 || defined SUNOS4 
+#if (defined _WIN32 && !defined WINCE) || defined SUNOS4
 
 #define fd_acos acos
 #define fd_asin asin
@@ -268,7 +268,7 @@ 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));
index e0c87b1fcd3943bc89eb3e0e0932af43d53a6deb..968e98b84167c6593ad27683e274b08829726838 100644 (file)
@@ -1131,7 +1131,7 @@ js_TransferScopeLock(JSContext *cx, JSScope *oldscope, JSScope *newscope)
      * state update.
      */
     if (!oldscope)
-       return;
+        return;
     JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, oldscope));
 
     /*
@@ -1141,7 +1141,7 @@ js_TransferScopeLock(JSContext *cx, JSScope *oldscope, JSScope *newscope)
      * was actually locked.
      */
     if (CX_THREAD_IS_RUNNING_GC(cx))
-       return;
+        return;
 
     /*
      * Special case in js_LockObj and js_UnlockScope for locking the sealed
index 9ece59c9b9823c074dce1ffa61d73726b6130f04..0ab71927b2d5c19ab99de5000d6b4df2fd8448f8 100644 (file)
@@ -106,28 +106,9 @@ typedef struct JSFatLockTable {
  * an #include cycle between jslock.h and jsscope.h: moderate-sized XXX here,
  * to be fixed by moving JS_LOCK_SCOPE to jsscope.h, JS_LOCK_OBJ to jsobj.h,
  * and so on.
- *
- * We also need jsscope.h #ifdef DEBUG for SET_OBJ_INFO and SET_SCOPE_INFO,
- * but we do not want any nested includes that depend on DEBUG.  Those lead
- * to build bustage when someone makes a change that depends in a subtle way
- * on jsscope.h being included directly or indirectly, but does not test by
- * building optimized as well as DEBUG.
  */
 #include "jsscope.h"
 
-#ifdef DEBUG
-
-#define SET_OBJ_INFO(obj_,file_,line_)                                        \
-    SET_SCOPE_INFO(OBJ_SCOPE(obj_),file_,line_)
-
-#define SET_SCOPE_INFO(scope_,file_,line_)                                    \
-    ((scope_)->ownercx ? (void)0 :                                            \
-     (JS_ASSERT((0 < (scope_)->u.count && (scope_)->u.count <= 4) ||          \
-                SCOPE_IS_SEALED(scope_)),                                     \
-      (void)((scope_)->file[(scope_)->u.count-1] = (file_),                   \
-             (scope_)->line[(scope_)->u.count-1] = (line_))))
-#endif /* DEBUG */
-
 #define JS_LOCK_RUNTIME(rt)         js_LockRuntime(rt)
 #define JS_UNLOCK_RUNTIME(rt)       js_UnlockRuntime(rt)
 
@@ -140,16 +121,14 @@ typedef struct JSFatLockTable {
  */
 #define JS_LOCK_OBJ(cx,obj)         ((OBJ_SCOPE(obj)->ownercx == (cx))        \
                                      ? (void)0                                \
-                                     : (js_LockObj(cx, obj),                  \
-                                        SET_OBJ_INFO(obj,__FILE__,__LINE__)))
+                                     : (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),                \
-                                      SET_SCOPE_INFO(scope,__FILE__,__LINE__)))
-#define JS_UNLOCK_SCOPE(cx,scope)   ((scope)->ownercx == (cx) ? (void)0 :     \
-                                     js_UnlockScope(cx, scope))
+#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)
 
@@ -279,11 +258,4 @@ extern JS_INLINE void js_Unlock(JSThinLock *tl, jsword me);
 #define JS_LOCK(P,CX)               JS_LOCK0(P,(CX)->thread)
 #define JS_UNLOCK(P,CX)             JS_UNLOCK0(P,(CX)->thread)
 
-#ifndef SET_OBJ_INFO
-#define SET_OBJ_INFO(obj,f,l)       ((void)0)
-#endif
-#ifndef SET_SCOPE_INFO
-#define SET_SCOPE_INFO(scope,f,l)   ((void)0)
-#endif
-
 #endif /* jslock_h___ */
index 2589bb7f929016363167d07a56dd17bfdead5016..95353ba1a0939473def9089eaa0c77b7f86d43c4 100644 (file)
@@ -1,39 +1,40 @@
-COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*-
-***** BEGIN LICENSE BLOCK *****
-Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
-The contents of this file are subject to the Mozilla Public License Version 
-1.1 (the "License"); you may not use this file except in compliance with 
-the License. You may obtain a copy of the License at 
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-for the specific language governing rights and limitations under the
-License.
-
-The Original Code is an OS/2 implementation of js_CompareAndSwap in assembly
-
-The Initial Developer of the Original Code is IBM Corporation.
-Portions created by the Initial Developer are Copyright (C) 2001
-the Initial Developer. All Rights Reserved.
-
-Contributor(s):
-
-Alternatively, the contents of this file may be used under the terms of
-either the GNU General Public License Version 2 or later (the "GPL"), or
-the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-in which case the provisions of the GPL or the LGPL are applicable instead
-of those above. If you wish to allow use of your version of this file only
-under the terms of either the GPL or the LGPL, and not to allow others to
-use your version of this file under the terms of the MPL, indicate your
-decision by deleting the provisions above and replace them with the notice
-and other provisions required by the GPL or the LGPL. If you do not delete
-the provisions above, a recipient may use your version of this file under
-the terms of any one of the MPL, the GPL or the LGPL.
-
-***** END LICENSE BLOCK *****
-        |
+; -*- 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
index 113c276d0e64d10bc6c68bb48056dde2108bb116..9bfca4dd31c975fff66b8797540363a21c1b4a27 100644 (file)
@@ -47,17 +47,17 @@ JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 n)
     JSIntn log2 = 0;
 
     if (n & (n-1))
-       log2++;
+        log2++;
     if (n >> 16)
-       log2 += 16, n >>= 16;
+        log2 += 16, n >>= 16;
     if (n >> 8)
-       log2 += 8, n >>= 8;
+        log2 += 8, n >>= 8;
     if (n >> 4)
-       log2 += 4, n >>= 4;
+        log2 += 4, n >>= 4;
     if (n >> 2)
-       log2 += 2, n >>= 2;
+        log2 += 2, n >>= 2;
     if (n >> 1)
-       log2++;
+        log2++;
     return log2;
 }
 
@@ -70,14 +70,14 @@ JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 n)
     JSIntn log2 = 0;
 
     if (n >> 16)
-       log2 += 16, n >>= 16;
+        log2 += 16, n >>= 16;
     if (n >> 8)
-       log2 += 8, n >>= 8;
+        log2 += 8, n >>= 8;
     if (n >> 4)
-       log2 += 4, n >>= 4;
+        log2 += 4, n >>= 4;
     if (n >> 2)
-       log2 += 2, n >>= 2;
+        log2 += 2, n >>= 2;
     if (n >> 1)
-       log2++;
+        log2++;
     return log2;
 }
index 76259e502ea1abe5959c9c711195428fe2306c3f..9a4a5b4d789a3f3502795be740b70ea3002090b3 100644 (file)
@@ -74,10 +74,10 @@ static void norm_udivmod32(JSUint32 *qp, JSUint32 *rp, JSUint64 a, JSUint32 b)
     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;
-       }
+        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;
@@ -87,9 +87,9 @@ static void norm_udivmod32(JSUint32 *qp, JSUint32 *rp, JSUint64 a, JSUint32 b)
     if (r0 < m) {
         q0--, r0 += b;
         if (r0 >= b
-           && r0 < m) {
-           q0--, r0 += b;
-       }
+            && r0 < m) {
+            q0--, r0 += b;
+        }
     }
     *qp = (q1 << 16) | q0;
     *rp = r0 - m;
@@ -101,17 +101,17 @@ static JSUint32 CountLeadingZeros(JSUint32 a)
     JSUint32 r = 32;
 
     if ((t = a >> 16) != 0)
-       r -= 16, a = t;
+        r -= 16, a = t;
     if ((t = a >> 8) != 0)
-       r -= 8, a = t;
+        r -= 8, a = t;
     if ((t = a >> 4) != 0)
-       r -= 4, a = t;
+        r -= 4, a = t;
     if ((t = a >> 2) != 0)
-       r -= 2, a = t;
+        r -= 2, a = t;
     if ((t = a >> 1) != 0)
-       r -= 1, a = t;
+        r -= 1, a = t;
     if (a & 1)
-       r--;
+        r--;
     return r;
 }
 
@@ -125,157 +125,157 @@ JS_PUBLIC_API(void) jsll_udivmod(JSUint64 *qp, JSUint64 *rp, JSUint64 a, JSUint6
     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;
-       }
+        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 (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;
+        qp->lo = q0;
+        qp->hi = q1;
     }
 }
 #endif /* !JS_HAVE_LONG_LONG */
index bde8bfbbf17d7abcfa7b4b584fabbb4c1e2bff1f..059cf00bb2293e7d0863ffecd023dc2a8e118755 100644 (file)
@@ -185,7 +185,7 @@ extern JS_PUBLIC_API(JSInt64) JSLL_Zero(void);
 /***********************************************************************
 ** MACROS:      JSLL_UDIVMOD
 ** DESCRIPTION:
-**  Produce both a quotient and a remainder given an unsigned 
+**  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
index 9c6fcec0e43abebb668d48c482b86c77cc5cf98f..19005eafa2e26f25f55dc3d363286d0a92ad2154 100644 (file)
 #include "jsobj.h"
 
 #ifndef M_E
-#define M_E            2.7182818284590452354
+#define M_E             2.7182818284590452354
 #endif
 #ifndef M_LOG2E
-#define M_LOG2E                1.4426950408889634074
+#define M_LOG2E         1.4426950408889634074
 #endif
 #ifndef M_LOG10E
-#define M_LOG10E       0.43429448190325182765
+#define M_LOG10E        0.43429448190325182765
 #endif
 #ifndef M_LN2
-#define M_LN2          0.69314718055994530942
+#define M_LN2           0.69314718055994530942
 #endif
 #ifndef M_LN10
-#define M_LN10         2.30258509299404568402
+#define M_LN10          2.30258509299404568402
 #endif
 #ifndef M_PI
-#define M_PI           3.14159265358979323846
+#define M_PI            3.14159265358979323846
 #endif
 #ifndef M_SQRT2
-#define M_SQRT2                1.41421356237309504880
+#define M_SQRT2         1.41421356237309504880
 #endif
 #ifndef M_SQRT1_2
-#define M_SQRT1_2      0.70710678118654752440
+#define M_SQRT1_2       0.70710678118654752440
 #endif
 
 static JSConstDoubleSpec math_constants[] = {
@@ -129,10 +129,6 @@ math_asin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
     if (!js_ValueToNumber(cx, argv[0], &x))
         return JS_FALSE;
-#ifdef XP_MAC
-    if (x == 0)
-        return js_NewNumberValue(cx, x, rval);
-#endif    
     z = fd_asin(x);
     return js_NewNumberValue(cx, z, rval);
 }
@@ -144,10 +140,6 @@ math_atan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
     if (!js_ValueToNumber(cx, argv[0], &x))
         return JS_FALSE;
-#ifdef XP_MAC
-    if (x == 0)
-        return js_NewNumberValue(cx, x, rval);
-#endif    
     z = fd_atan(x);
     return js_NewNumberValue(cx, z, rval);
 }
@@ -158,9 +150,9 @@ 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;
+        return JS_FALSE;
     if (!js_ValueToNumber(cx, argv[1], &y))
-       return JS_FALSE;
+        return JS_FALSE;
     z = fd_atan2(x, y);
     return js_NewNumberValue(cx, z, rval);
 }
@@ -288,9 +280,19 @@ 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;
+        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);
 }
@@ -316,7 +318,7 @@ random_init(JSRuntime *rt)
 
     /* Do at most once. */
     if (rt->rngInitialized)
-       return;
+        return;
     rt->rngInitialized = JS_TRUE;
 
     /* rt->rngMultiplier = 0x5DEECE66DL */
@@ -429,7 +431,7 @@ math_tan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 #if JS_HAS_TOSOURCE
 static JSBool
 math_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+              jsval *rval)
 {
     *rval = ATOM_KEY(cx->runtime->atomState.MathAtom);
     return JS_TRUE;
@@ -438,26 +440,26 @@ math_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
 static JSFunctionSpec math_static_methods[] = {
 #if JS_HAS_TOSOURCE
-    {js_toSource_str,   math_toSource,         0, 0, 0},
+    {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},
+    {"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}
 };
 
@@ -465,7 +467,7 @@ JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj)
 {
     JSObject *Math;
-    
+
     Math = JS_DefineObject(cx, obj, "Math", &math_class, NULL, 0);
     if (!Math)
         return NULL;
index 7a6b21657bc68aae10d9c359de56c967c0c1f07f..b67dba1deb79e9aabfffdad994c6165af9075330 100644 (file)
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and 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"),
index 9de1d72db72c29c4bbc19d201624d8b7a0114827..8a5596304e3d84c26a975ab82c6d6598c03a8c07 100644 (file)
@@ -114,25 +114,25 @@ num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rva
 static JSBool
 num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    JSString *str;
     jsint radix;
+    JSString *str;
     jsdouble d;
     const jschar *bp, *ep;
 
-    str = js_ValueToString(cx, argv[0]);
-    if (!str)
-        return JS_FALSE;
-
     if (argc > 1) {
         if (!js_ValueToECMAInt32(cx, argv[1], &radix))
             return JS_FALSE;
-    } else
+    } 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)
@@ -161,7 +161,7 @@ static JSFunctionSpec number_functions[] = {
     {0,0,0,0,0}
 };
 
-static JSClass number_class = {
+JSClass js_NumberClass = {
     "Number",
     JSCLASS_HAS_PRIVATE,
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
@@ -201,7 +201,7 @@ num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     char buf[64];
     JSString *str;
 
-    if (!JS_InstanceOf(cx, obj, &number_class, argv))
+    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));
@@ -211,7 +211,7 @@ num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
-    JS_snprintf(buf, sizeof buf, "(new %s(%s))", number_class.name, numStr);
+    JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
     str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return JS_FALSE;
@@ -256,7 +256,7 @@ num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     jsint base;
     JSString *str;
 
-    if (!JS_InstanceOf(cx, obj, &number_class, argv))
+    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));
@@ -385,7 +385,7 @@ num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
 static JSBool
 num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    if (!JS_InstanceOf(cx, obj, &number_class, argv))
+    if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv))
         return JS_FALSE;
     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
     return JS_TRUE;
@@ -404,7 +404,7 @@ num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDTo
     JSString *str;
     char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */
 
-    if (!JS_InstanceOf(cx, obj, &number_class, argv))
+    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));
@@ -505,6 +505,7 @@ static jsdouble NaN;
 
 
 #if (defined XP_WIN || defined XP_OS2) &&                                     \
+    !defined WINCE &&                                                         \
     !defined __MWERKS__ &&                                                    \
     (defined _M_IX86 ||                                                       \
      (defined __GNUC__ && !defined __MINGW32__))
@@ -537,27 +538,23 @@ js_InitRuntimeNumberState(JSContext *cx)
     u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
     u.s.lo = 0xffffffff;
     number_constants[NC_NaN].dval = NaN = u.d;
-    rt->jsNaN = js_NewDouble(cx, NaN);
-    if (!rt->jsNaN || !js_LockGCThing(cx, rt->jsNaN))
+    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);
-    if (!rt->jsPositiveInfinity ||
-        !js_LockGCThing(cx, rt->jsPositiveInfinity)) {
+    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);
-    if (!rt->jsNegativeInfinity ||
-        !js_LockGCThing(cx, rt->jsNegativeInfinity)) {
+    rt->jsNegativeInfinity = js_NewDouble(cx, u.d, GCF_LOCK);
+    if (!rt->jsNegativeInfinity)
         return JS_FALSE;
-    }
 
     u.s.hi = 0;
     u.s.lo = 1;
@@ -605,7 +602,7 @@ js_InitNumberClass(JSContext *cx, JSObject *obj)
     if (!JS_DefineFunctions(cx, obj, number_functions))
         return NULL;
 
-    proto = JS_InitClass(cx, obj, NULL, &number_class, Number, 1,
+    proto = JS_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1,
                          NULL, number_methods, NULL, NULL);
     if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
         return NULL;
@@ -630,11 +627,11 @@ js_InitNumberClass(JSContext *cx, JSObject *obj)
 }
 
 jsdouble *
-js_NewDouble(JSContext *cx, jsdouble d)
+js_NewDouble(JSContext *cx, jsdouble d, uintN gcflag)
 {
     jsdouble *dp;
 
-    dp = (jsdouble *) js_AllocGCThing(cx, GCX_DOUBLE);
+    dp = (jsdouble *) js_NewGCThing(cx, gcflag | GCX_DOUBLE, sizeof(jsdouble));
     if (!dp)
         return NULL;
     *dp = d;
@@ -652,7 +649,7 @@ js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
 {
     jsdouble *dp;
 
-    dp = js_NewDouble(cx, d);
+    dp = js_NewDouble(cx, d, 0);
     if (!dp)
         return JS_FALSE;
     *rval = DOUBLE_TO_JSVAL(dp);
@@ -679,7 +676,7 @@ js_NumberToObject(JSContext *cx, jsdouble d)
     JSObject *obj;
     jsval v;
 
-    obj = js_NewObject(cx, &number_class, NULL, NULL);
+    obj = js_NewObject(cx, &js_NumberClass, NULL, NULL);
     if (!obj)
         return NULL;
     if (!js_NewNumberValue(cx, d, &v)) {
index 28f40e6ecb800a82e0e30b92ff2816310e4ca38a..cd99501e77fc6663a1ec96f04573b906563b9ff7 100644 (file)
@@ -67,9 +67,9 @@ JS_BEGIN_EXTERN_C
 typedef union jsdpun {
     struct {
 #if defined(IS_LITTLE_ENDIAN) && !defined(CPU_IS_ARM)
-       uint32 lo, hi;
+        uint32 lo, hi;
 #else
-       uint32 hi, lo;
+        uint32 hi, lo;
 #endif
     } s;
     jsdouble d;
@@ -124,7 +124,7 @@ typedef union jsdpun {
     ((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_LO32(d) == 0)
 
 /*
  * JSDOUBLE_IS_INT first checks that d is neither NaN nor infinite, to avoid
@@ -134,7 +134,16 @@ typedef union jsdpun {
  */
 #define JSDOUBLE_IS_INT(d, i) (JSDOUBLE_IS_FINITE(d)                          \
                                && !JSDOUBLE_IS_NEGZERO(d)                     \
-                              && ((d) == (i = (jsint)(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
@@ -144,6 +153,8 @@ 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);
 
@@ -159,7 +170,7 @@ extern const char js_parseInt_str[];
 
 /* GC-allocate a new JS number. */
 extern jsdouble *
-js_NewDouble(JSContext *cx, jsdouble d);
+js_NewDouble(JSContext *cx, jsdouble d, uintN gcflag);
 
 extern void
 js_FinalizeDouble(JSContext *cx, jsdouble *dp);
index 847040c615f7615905d0f6453ca6f6fee40bc19e..03a5980940a96550160b0f7ab5c04684a08bc720 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
 
 #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
 
@@ -77,17 +82,9 @@ js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop);
 #define NATIVE_DROP_PROPERTY NULL
 #endif
 
-#ifdef XP_MAC
-#pragma export on
-#endif
-
 JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
     js_NewObjectMap,        js_DestroyObjectMap,
-#if defined JS_THREADSAFE && defined DEBUG
-    _js_LookupProperty,     js_DefineProperty,
-#else
     js_LookupProperty,      js_DefineProperty,
-#endif
     js_GetProperty,         js_SetProperty,
     js_GetAttributes,       js_SetAttributes,
     js_DeleteProperty,      js_DefaultValue,
@@ -100,10 +97,6 @@ JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
     js_GetRequiredSlot,     js_SetRequiredSlot
 };
 
-#ifdef XP_MAC
-#pragma export off
-#endif
-
 JSClass js_ObjectClass = {
     js_Object_str,
     0,
@@ -152,20 +145,39 @@ 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)) {
-        id = (jsid)cx->runtime->atomState.protoAtom;
+        propid = ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
         mode = JSACC_PROTO;
     } else {
-        id = (jsid)cx->runtime->atomState.parentAtom;
+        propid = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);
         mode = JSACC_PARENT;
     }
-    if (!OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, &attrs))
+
+    /* 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;
-    *vp = OBJ_GET_SLOT(cx, obj, slot);
+
+    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;
 }
 
@@ -174,6 +186,7 @@ obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     JSObject *pobj;
     uint32 slot;
+    jsid propid;
     uintN attrs;
 
     if (!JSVAL_IS_OBJECT(*vp))
@@ -184,7 +197,8 @@ obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
         return JS_FALSE;
 
     /* __parent__ is readonly and permanent, only __proto__ may be set. */
-    if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_PROTO | JSACC_WRITE, vp, &attrs))
+    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);
@@ -375,7 +389,7 @@ js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj)
 JS_STATIC_DLL_CALLBACK(JSHashNumber)
 js_hash_object(const void *key)
 {
-    return (JSHashNumber)key >> JSVAL_TAGBITS;
+    return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
 }
 
 static JSHashEntry *
@@ -396,6 +410,12 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
     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;
@@ -404,14 +424,25 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
     he = *hep;
     if (!he) {
         sharpid = 0;
-        he = JS_HashTableRawAdd(table, hep, hash, obj, (void *)sharpid);
+        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];
@@ -419,29 +450,29 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
             ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
             if (!ok)
                 break;
-            if (prop) {
-                ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs);
-                if (ok) {
-                    if (OBJ_IS_NATIVE(obj2) &&
-                        (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
-                        val = JSVAL_NULL;
-                        if (attrs & JSPROP_GETTER)
-                            val = (jsval) ((JSScopeProperty*)prop)->getter;
-                        if (attrs & JSPROP_SETTER) {
-                            if (val != JSVAL_NULL) {
-                                /* Mark the getter, then set val to setter. */
-                                ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val),
-                                                       NULL)
-                                      != NULL);
-                            }
-                            val = (jsval) ((JSScopeProperty*)prop)->setter;
+            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);
                         }
-                    } else {
-                        ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
+                        val = (jsval) ((JSScopeProperty*)prop)->setter;
                     }
+                } else {
+                    ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
                 }
-                OBJ_DROP_PROPERTY(cx, obj2, prop);
             }
+            OBJ_DROP_PROPERTY(cx, obj2, prop);
 #else
             ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
 #endif
@@ -458,10 +489,10 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
         if (!ok)
             return NULL;
     } else {
-        sharpid = (jsatomid) he->value;
+        sharpid = JS_PTR_TO_UINT32(he->value);
         if (sharpid == 0) {
             sharpid = ++map->sharpgen << SHARP_ID_SHIFT;
-            he->value = (void *) sharpid;
+            he->value = JS_UINT32_TO_PTR(sharpid);
         }
         ida = NULL;
     }
@@ -483,6 +514,12 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
     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;
@@ -495,14 +532,16 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
             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((((jsatomid) he->value) & SHARP_BIT) == 0);
+        JS_ASSERT((JS_PTR_TO_UINT32(he->value) & SHARP_BIT) == 0);
         if (!idap) {
             JS_DestroyIdArray(cx, ida);
             ida = NULL;
@@ -525,20 +564,17 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
                 JS_ReportOutOfMemory(cx);
                 goto bad;
             }
-            *sp = NULL;
             sharpid = 0;
             goto out;
         }
     }
 
-    sharpid = (jsatomid) he->value;
-    if (sharpid == 0) {
-        *sp = NULL;
-    } else {
+    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);
+        *sp = js_InflateString(cx, buf, &len);
         if (!*sp) {
             if (ida)
                 JS_DestroyIdArray(cx, ida);
@@ -569,6 +605,7 @@ out:
 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;
@@ -585,6 +622,7 @@ js_LeaveSharpObject(JSContext *cx, JSIdArray **idap)
     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;
@@ -598,7 +636,43 @@ js_LeaveSharpObject(JSContext *cx, JSIdArray **idap)
     }
 }
 
-#define OBJ_TOSTRING_EXTRA      3       /* for 3 local GC roots */
+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
@@ -610,7 +684,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     JSIdArray *ida;
     jschar *chars, *ochars, *vsharp;
     const jschar *idstrchars, *vchars;
-    size_t nchars, idstrlength, gsoplength, vlength, vsharplength;
+    size_t nchars, idstrlength, gsoplength, vlength, vsharplength, curlen;
     char *comma;
     jsint i, j, length, valcnt;
     jsid id;
@@ -619,7 +693,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     JSProperty *prop;
     uintN attrs;
 #endif
-    jsval val[2];
+    jsval *val;
     JSString *gsop[2];
     JSAtom *atom;
     JSString *idstr, *valstr, *str;
@@ -634,7 +708,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
      * obj_toString for 1.2 calls toSource, and doesn't want the extra parens
      * on the outside.
      */
-    outermost = (cx->version != JSVERSION_1_2 && cx->sharpObjectMap.depth == 0);
+    outermost = !JS_VERSION_IS_1_2(cx) && cx->sharpObjectMap.depth == 0;
     he = js_EnterSharpObject(cx, obj, &ida, &chars);
     if (!he)
         return JS_FALSE;
@@ -729,6 +803,13 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
     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];
@@ -789,14 +870,14 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
             goto error;
 
         /* Convert id to a jsval and then to a string. */
-        atom = JSVAL_IS_INT(id) ? NULL : (JSAtom *)id;
+        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;
         }
-        argv[0] = STRING_TO_JSVAL(idstr);
+        *rval = STRING_TO_JSVAL(idstr);         /* local root */
 
         /*
          * If id is a string that's a reserved identifier, or else id is not
@@ -805,13 +886,13 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
          */
         if (atom
             ? (ATOM_KEYWORD(atom) || !js_IsIdentifier(idstr))
-            : JSVAL_TO_INT(id) < 0) {
+            : (JSID_IS_OBJECT(id) || JSID_TO_INT(id) < 0)) {
             idstr = js_QuoteString(cx, idstr, (jschar)'\'');
             if (!idstr) {
                 ok = JS_FALSE;
                 goto error;
             }
-            argv[0] = STRING_TO_JSVAL(idstr);
+            *rval = STRING_TO_JSVAL(idstr);     /* local root */
         }
         idstrchars = JSSTRING_CHARS(idstr);
         idstrlength = JSSTRING_LENGTH(idstr);
@@ -823,16 +904,19 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                 ok = JS_FALSE;
                 goto error;
             }
-            argv[1+j] = STRING_TO_JSVAL(valstr);
+            argv[j] = STRING_TO_JSVAL(valstr);  /* local root */
             vchars = JSSTRING_CHARS(valstr);
             vlength = JSSTRING_LENGTH(valstr);
 
 #ifndef OLD_GETTER_SETTER
-            /* Remove 'function ' from beginning of valstr. */
+            /*
+             * 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) + 1;
+                int n = strlen(js_function_str) + 2;
                 vchars += n;
-                vlength -= n;
+                vlength -= n + 1;
             }
 #endif
 
@@ -860,14 +944,31 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
             }
 #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),
-                        (nchars + (comma ? 2 : 0) +
-                         idstrlength + 1 +
-                         (gsop[j] ? 1 + JSSTRING_LENGTH(gsop[j]) : 0) +
-                         vsharplength + vlength +
-                         (outermost ? 2 : 1) + 1) * sizeof(jschar));
+                realloc((ochars = chars), curlen * sizeof(jschar));
             if (!chars) {
                 /* Save code space on error: let JS_free ignore null vsharp. */
                 JS_free(cx, vsharp);
@@ -945,6 +1046,12 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     }
     *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 */
 
@@ -958,7 +1065,7 @@ js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     JSString *str;
 
 #if JS_HAS_INITIALIZERS
-    if (cx->version == JSVERSION_1_2)
+    if (JS_VERSION_IS_1_2(cx))
         return js_obj_toSource(cx, obj, argc, argv, rval);
 #endif
 
@@ -986,6 +1093,20 @@ js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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)
 {
@@ -993,6 +1114,69 @@ obj_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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)
 {
@@ -1007,14 +1191,15 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     JSBool ok;
 #if JS_HAS_EVAL_THIS_SCOPE
     JSObject *callerScopeChain = NULL, *callerVarObj = NULL;
-    JSBool setCallerScopeChain = JS_FALSE, setCallerVarObj = JS_FALSE;
+    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 (JSVERSION_IS_ECMA(cx->version) &&
+    if (JS_VERSION_IS_ECMA(cx) &&
         indirectCall &&
         !JS_ReportErrorFlagsAndNumber(cx,
                                       JSREPORT_WARNING | JSREPORT_STRICT,
@@ -1029,6 +1214,14 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         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
@@ -1048,14 +1241,21 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         if (indirectCall) {
             callerScopeChain = caller->scopeChain;
             if (obj != callerScopeChain) {
-                scopeobj = js_NewObject(cx, &js_WithClass, 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;
-                setCallerScopeChain = JS_TRUE;
+
+                /* Remember scopeobj so we can null its private when done. */
+                setCallerScopeChain = scopeobj;
             }
 
             callerVarObj = caller->varobj;
@@ -1078,6 +1278,11 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 #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;
@@ -1089,7 +1294,18 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         principals = NULL;
     }
 
-    fp->flags |= JSFRAME_EVAL;
+    /*
+     * 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),
@@ -1109,14 +1325,25 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             scopeobj = caller->scopeChain;
     }
 #endif
-    ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
+
+    /*
+     * 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)
+    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
@@ -1129,13 +1356,37 @@ 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;
-    JSObject *funobj;
     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;
@@ -1145,11 +1396,10 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp,
         return JS_TRUE;
     generation = cx->resolvingTable->generation;
 
-    funobj = (JSObject *) closure;
     argv[0] = id;
     argv[1] = old;
     argv[2] = *nvp;
-    ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(funobj), 3, argv, nvp);
+    ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(callable), 3, argv, nvp);
     js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation);
     return ok;
 }
@@ -1157,21 +1407,14 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp,
 static JSBool
 obj_watch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    JSObject *funobj;
-    JSFunction *fun;
+    JSObject *callable;
     jsval userid, value;
     jsid propid;
     uintN attrs;
 
-    if (JSVAL_IS_FUNCTION(cx, argv[1])) {
-        funobj = JSVAL_TO_OBJECT(argv[1]);
-    } else {
-        fun = js_ValueToFunction(cx, &argv[1], 0);
-        if (!fun)
-            return JS_FALSE;
-        funobj = fun->object;
-    }
-    argv[1] = OBJECT_TO_JSVAL(funobj);
+    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];
@@ -1182,7 +1425,7 @@ obj_watch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         return JS_FALSE;
     if (attrs & JSPROP_READONLY)
         return JS_TRUE;
-    return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, funobj);
+    return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, callable);
 }
 
 static JSBool
@@ -1203,6 +1446,14 @@ obj_unwatch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 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;
@@ -1211,17 +1462,44 @@ obj_hasOwnProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
     if (!JS_ValueToId(cx, argv[0], &id))
         return JS_FALSE;
-    if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+    if (!lookup(cx, obj, id, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         *rval = JSVAL_FALSE;
     } else if (obj2 == obj) {
         *rval = JSVAL_TRUE;
-    } else if (OBJ_IS_NATIVE(obj2)) {
-        sprop = (JSScopeProperty *)prop;
-        *rval = BOOLEAN_TO_JSVAL(SPROP_IS_SHARED_PERMANENT(sprop));
     } else {
-        *rval = JSVAL_FALSE;
+        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);
@@ -1425,7 +1703,7 @@ static JSFunctionSpec object_methods[] = {
     {js_toSource_str,             js_obj_toSource,    0, 0, OBJ_TOSTRING_EXTRA},
 #endif
     {js_toString_str,             js_obj_toString,    0, 0, OBJ_TOSTRING_EXTRA},
-    {js_toLocaleString_str,       js_obj_toString,    0, 0, OBJ_TOSTRING_EXTRA},
+    {js_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
@@ -1474,49 +1752,12 @@ Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
  */
 static JSBool
 with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
-                    JSProperty **propp
-#if defined JS_THREADSAFE && defined DEBUG
-                    , const char *file, uintN line
-#endif
-                    )
+                    JSProperty **propp)
 {
-    JSObject *proto;
-    JSScopeProperty *sprop;
-    JSStackFrame *fp;
-
-    proto = OBJ_GET_PROTO(cx, obj);
+    JSObject *proto = OBJ_GET_PROTO(cx, obj);
     if (!proto)
         return js_LookupProperty(cx, obj, id, objp, propp);
-    if (!OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp))
-        return JS_FALSE;
-
-    /*
-     * Check whether id names an argument or local variable in an active
-     * function.  If so, pretend we didn't find it, so that the real arg or
-     * var property can be found in the function's call object, later on in
-     * the scope chain.  But skip unshared arg and var properties -- those
-     * result when a script explicitly sets a function "static" property of
-     * the same name.  See jsinterp.c:SetFunctionSlot.
-     *
-     * XXX blame pre-ECMA reflection of function args and vars as properties
-     */
-    if ((sprop = (JSScopeProperty *) *propp) &&
-        (proto = *objp, OBJ_IS_NATIVE(proto)) &&
-        (sprop->getter == js_GetArgument ||
-         sprop->getter == js_GetLocalVariable) &&
-        (sprop->attrs & JSPROP_SHARED)) {
-        JS_ASSERT(OBJ_GET_CLASS(cx, proto) == &js_FunctionClass);
-        for (fp = cx->fp; fp && (!fp->fun || !fp->fun->interpreted);
-             fp = fp->down) {
-            continue;
-        }
-        if (fp && fp->fun == (JSFunction *) JS_GetPrivate(cx, proto)) {
-            OBJ_DROP_PROPERTY(cx, proto, *propp);
-            *objp = NULL;
-            *propp = NULL;
-        }
-    }
-    return JS_TRUE;
+    return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp);
 }
 
 static JSBool
@@ -1627,13 +1868,26 @@ with_getObjectOps(JSContext *cx, JSClass *clasp)
 
 JSClass js_WithClass = {
     "With",
-    0,
+    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)
@@ -1650,7 +1904,7 @@ With(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     }
 
     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
-        obj = js_NewObject(cx, &js_WithClass, NULL, NULL);
+        obj = js_NewWithObject(cx, NULL, NULL, -1);
         if (!obj)
             return JS_FALSE;
         *rval = OBJECT_TO_JSVAL(obj);
@@ -1696,11 +1950,13 @@ js_InitObjectClass(JSContext *cx, JSObject *obj)
 #endif
 
     /* ECMA (15.1.2.1) says 'eval' is also a property of the global object. */
-    if (!OBJ_GET_PROPERTY(cx, proto, (jsid)cx->runtime->atomState.evalAtom,
+    if (!OBJ_GET_PROPERTY(cx, proto,
+                          ATOM_TO_JSID(cx->runtime->atomState.evalAtom),
                           &eval)) {
         return NULL;
     }
-    if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)cx->runtime->atomState.evalAtom,
+    if (!OBJ_DEFINE_PROPERTY(cx, obj,
+                             ATOM_TO_JSID(cx->runtime->atomState.evalAtom),
                              eval, NULL, NULL, 0, NULL)) {
         return NULL;
     }
@@ -1757,28 +2013,87 @@ 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, *ctor;
+    JSObject *obj;
     JSObjectOps *ops;
     JSObjectMap *map;
     JSClass *protoclasp;
-    jsval cval;
     uint32 nslots, i;
     jsval *newslots;
-
-    /* Allocate an object from the GC heap and zero it. */
-    obj = (JSObject *) js_AllocGCThing(cx, GCX_OBJECT);
-    if (!obj)
-        return NULL;
+    JSTempValueRooter tvr;
 
     /* Bootstrap the ur-object, and make it the default prototype object. */
     if (!proto) {
         if (!GetClassPrototype(cx, parent, clasp->name, &proto))
-            goto bad;
+            return NULL;
         if (!proto && !GetClassPrototype(cx, parent, js_Object_str, &proto))
-            goto bad;
+            return NULL;
     }
 
     /* Always call the class's getObjectOps hook if it has one. */
@@ -1786,6 +2101,23 @@ js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
           ? 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
@@ -1802,16 +2134,12 @@ js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
              (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&
           protoclasp->reserveSlots == clasp->reserveSlots)))
     {
-        /* Default parent to the parent of the prototype's constructor. */
-        if (!parent) {
-            if (!OBJ_GET_PROPERTY(cx, proto,
-                                  (jsid)cx->runtime->atomState.constructorAtom,
-                                  &cval)) {
-                goto bad;
-            }
-            if (JSVAL_IS_OBJECT(cval) && (ctor = JSVAL_TO_OBJECT(cval)) != NULL)
-                parent = OBJ_GET_PARENT(cx, ctor);
-        }
+        /*
+         * 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);
@@ -1830,14 +2158,12 @@ js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
     }
 
     /* Allocate a slots vector, with a -1'st element telling its length. */
-    newslots = (jsval *) JS_malloc(cx, (nslots + 1) * sizeof(jsval));
+    newslots = AllocSlots(cx, NULL, nslots);
     if (!newslots) {
         js_DropObjectMap(cx, obj->map, obj);
         obj->map = NULL;
         goto bad;
     }
-    newslots[0] = nslots;
-    newslots++;
 
     /* Set the proto, parent, and class properties. */
     newslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
@@ -1857,15 +2183,18 @@ js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
         JS_UNKEEP_ATOMS(cx->runtime);
     }
 
+out:
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    cx->newborn[GCX_OBJECT] = (JSGCThing *) obj;
     return obj;
 
 bad:
-    cx->newborn[GCX_OBJECT] = NULL;
-    return NULL;
+    obj = NULL;
+    goto out;
 }
 
-static JSBool
-FindConstructor(JSContext *cx, JSObject *start, const char *name, jsval *vp)
+JSBool
+js_FindConstructor(JSContext *cx, JSObject *start, const char *name, jsval *vp)
 {
     JSAtom *atom;
     JSObject *obj, *pobj;
@@ -1891,12 +2220,8 @@ FindConstructor(JSContext *cx, JSObject *start, const char *name, jsval *vp)
     }
 
     JS_ASSERT(OBJ_IS_NATIVE(obj));
-    if (!js_LookupPropertyWithFlags(cx, obj, (jsid)atom, JSRESOLVE_CLASSNAME,
-                                    &pobj, &prop
-#if defined JS_THREADSAFE && defined DEBUG
-                                    , __FILE__, __LINE__
-#endif
-                                    )) {
+    if (!js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom),
+                                    JSRESOLVE_CLASSNAME, &pobj, &prop)) {
         return JS_FALSE;
     }
     if (!prop)  {
@@ -1917,15 +2242,27 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
                    JSObject *parent, uintN argc, jsval *argv)
 {
     jsval cval, rval;
+    JSTempValueRooter argtvr, tvr;
     JSObject *obj, *ctor;
 
-    if (!FindConstructor(cx, parent, clasp->name, &cval))
+    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.
@@ -1935,9 +2272,11 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
         parent = OBJ_GET_PARENT(cx, ctor);
     if (!proto) {
         if (!OBJ_GET_PROPERTY(cx, ctor,
-                              (jsid)cx->runtime->atomState.classPrototypeAtom,
+                              ATOM_TO_JSID(cx->runtime->atomState
+                                           .classPrototypeAtom),
                               &rval)) {
-            return NULL;
+            obj = NULL;
+            goto out;
         }
         if (JSVAL_IS_OBJECT(rval))
             proto = JSVAL_TO_OBJECT(rval);
@@ -1945,14 +2284,39 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
 
     obj = js_NewObject(cx, clasp, proto, parent);
     if (!obj)
-        return NULL;
+        goto out;
 
     if (!js_InternalConstruct(cx, obj, cval, argc, argv, &rval))
         goto bad;
-    return JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : obj;
+
+    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;
-    return NULL;
+    obj = NULL;
+    goto out;
 }
 
 void
@@ -1985,7 +2349,7 @@ js_FinalizeObject(JSContext *cx, JSObject *obj)
     /* Drop map and free slots. */
     js_DropObjectMap(cx, map, obj);
     obj->map = NULL;
-    JS_free(cx, obj->slots - 1);
+    FreeSlots(cx, obj->slots);
     obj->slots = NULL;
 }
 
@@ -1996,7 +2360,7 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
 {
     JSObjectMap *map;
     JSClass *clasp;
-    uint32 nslots, i;
+    uint32 nslots;
     jsval *newslots;
 
     map = obj->map;
@@ -2013,14 +2377,11 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
         JS_ASSERT(nslots >= JS_INITIAL_NSLOTS);
         nslots += (nslots + 1) / 2;
 
-        newslots = (jsval *)
-            JS_realloc(cx, obj->slots - 1, (nslots + 1) * sizeof(jsval));
+        newslots = AllocSlots(cx, obj->slots, nslots);
         if (!newslots)
             return JS_FALSE;
-        for (i = 1 + newslots[0]; i <= nslots; i++)
-            newslots[i] = JSVAL_VOID;
-        newslots[0] = map->nslots = nslots;
-        obj->slots = newslots + 1;
+        map->nslots = nslots;
+        obj->slots = newslots;
     }
 
 #ifdef TOO_MUCH_GC
@@ -2050,19 +2411,18 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
         if (nslots < JS_INITIAL_NSLOTS)
             nslots = JS_INITIAL_NSLOTS;
 
-        newslots = (jsval *)
-            JS_realloc(cx, obj->slots - 1, (nslots + 1) * sizeof(jsval));
+        newslots = AllocSlots(cx, obj->slots, nslots);
         if (!newslots)
             return;
-        newslots[0] = map->nslots = nslots;
-        obj->slots = newslots + 1;
+        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)                                       \
+        if (JSSTRING_LENGTH(str_) == 0)                                       \
             id = JSVAL_ZERO;                                                  \
     JS_END_MACRO
 #else
@@ -2072,17 +2432,18 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
 /* JSVAL_INT_MAX as a string */
 #define JSVAL_INT_MAX_STRING "1073741823"
 
-#define CHECK_FOR_FUNNY_INDEX(id)                                             \
+#define CHECK_FOR_STRING_INDEX(id)                                            \
     JS_BEGIN_MACRO                                                            \
-        if (!JSVAL_IS_INT(id)) {                                              \
-            JSAtom *atom_ = (JSAtom *)id;                                     \
+        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_) &&                                            \
-                str_->length - negative_ <= sizeof(JSVAL_INT_MAX_STRING)-1) { \
-                id = CheckForFunnyIndex(id, cp_, negative_);                  \
+            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);                                    \
             }                                                                 \
@@ -2090,7 +2451,8 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
     JS_END_MACRO
 
 static jsid
-CheckForFunnyIndex(jsid id, const jschar *cp, JSBool negative)
+CheckForStringIndex(jsid id, const jschar *cp, const jschar *end,
+                    JSBool negative)
 {
     jsuint index = JS7_UNDEC(*cp++);
     jsuint oldIndex = 0;
@@ -2104,17 +2466,66 @@ CheckForFunnyIndex(jsid id, const jschar *cp, JSBool negative)
             cp++;
         }
     }
-    if (*cp == 0 &&
+    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_JSVAL((jsint)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,
@@ -2132,7 +2543,7 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
          * Handle old bug that took empty string as zero index.  Also convert
          * string indices to integers if appropriate.
          */
-        CHECK_FOR_FUNNY_INDEX(id);
+        CHECK_FOR_STRING_INDEX(id);
         sprop = js_AddScopeProperty(cx, scope, id, getter, setter, slot, attrs,
                                     flags, shortid);
     }
@@ -2172,6 +2583,26 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
                                    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,
@@ -2186,7 +2617,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
      * Handle old bug that took empty string as zero index.  Also convert
      * string indices to integers if appropriate.
      */
-    CHECK_FOR_FUNNY_INDEX(id);
+    CHECK_FOR_STRING_INDEX(id);
 
 #if JS_HAS_GETTER_SETTER
     /*
@@ -2257,15 +2688,15 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
     if (!sprop)
         goto bad;
 
-    /* XXXbe called with lock held */
-    if (!clasp->addProperty(cx, obj, SPROP_USERID(sprop), &value)) {
-        (void) js_RemoveScopeProperty(cx, scope, id);
-        goto bad;
-    }
-
+    /* 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
@@ -2294,6 +2725,8 @@ Detecting(JSContext *cx, jsbytecode *pc)
     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. */
@@ -2334,13 +2767,16 @@ Detecting(JSContext *cx, jsbytecode *pc)
     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
-#if defined JS_THREADSAFE && defined DEBUG
-                           , const char *file, uintN line
-#endif
-                           )
+                           JSObject **objp, JSProperty **propp)
 {
     JSObject *start, *obj2, *proto;
     JSScope *scope;
@@ -2360,13 +2796,12 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
      * Handle old bug that took empty string as zero index.  Also convert
      * string indices to integers if appropriate.
      */
-    CHECK_FOR_FUNNY_INDEX(id);
+    CHECK_FOR_STRING_INDEX(id);
 
     /* Search scopes starting with obj and following the prototype link. */
     start = obj;
     for (;;) {
         JS_LOCK_OBJ(cx, obj);
-        SET_OBJ_INFO(obj, file, line);
         scope = OBJ_SCOPE(obj);
         if (scope->object == obj) {
             sprop = SCOPE_GET_PROPERTY(scope, id);
@@ -2406,7 +2841,9 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
 
                 if (clasp->flags & JSCLASS_NEW_RESOLVE) {
                     newresolve = (JSNewResolveOp)resolve;
-                    if (cx->fp && (pc = cx->fp->pc)) {
+                    if (!(flags & JSRESOLVE_CLASSNAME) &&
+                        cx->fp &&
+                        (pc = cx->fp->pc)) {
                         cs = &js_CodeSpec[*pc];
                         format = cs->format;
                         if ((format & JOF_MODEMASK) != JOF_NAME)
@@ -2435,7 +2872,6 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                         goto cleanup;
 
                     JS_LOCK_OBJ(cx, obj);
-                    SET_OBJ_INFO(obj, file, line);
                     if (obj2) {
                         /* Resolved: juggle locks and lookup id again. */
                         if (obj2 != obj) {
@@ -2463,7 +2899,10 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                             if (scope->object == obj2)
                                 sprop = SCOPE_GET_PROPERTY(scope, id);
                         }
-                        if (obj2 != obj && !sprop) {
+                        if (sprop) {
+                            JS_ASSERT(obj2 == scope->object);
+                            obj = obj2;
+                        } else if (obj2 != obj) {
                             JS_UNLOCK_OBJ(cx, obj2);
                             JS_LOCK_OBJ(cx, obj);
                         }
@@ -2478,7 +2917,6 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                     if (!ok)
                         goto cleanup;
                     JS_LOCK_OBJ(cx, obj);
-                    SET_OBJ_INFO(obj, file, line);
                     scope = OBJ_SCOPE(obj);
                     JS_ASSERT(MAP_IS_NATIVE(&scope->map));
                     if (scope->object == obj)
@@ -2515,22 +2953,6 @@ out:
     return JS_TRUE;
 }
 
-#if defined JS_THREADSAFE && defined DEBUG
-JS_FRIEND_API(JSBool)
-_js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
-                   JSProperty **propp, const char *file, uintN line)
-{
-    return js_LookupPropertyWithFlags(cx, obj, id, 0, objp, propp, file, line);
-}
-#else
-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);
-}
-#endif
-
 JS_FRIEND_API(JSBool)
 js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
                 JSProperty **propp)
@@ -2632,7 +3054,7 @@ js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
      * Handle old bug that took empty string as zero index.  Also convert
      * string indices to integers if appropriate.
      */
-    CHECK_FOR_FUNNY_INDEX(id);
+    CHECK_FOR_STRING_INDEX(id);
 
     if (!js_LookupProperty(cx, obj, id, &obj2, &prop))
         return JS_FALSE;
@@ -2641,7 +3063,7 @@ js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 
 #if JS_BUG_NULL_INDEX_PROPS
         /* Indexed properties defaulted to null in old versions. */
-        default_val = (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0)
+        default_val = (JSID_IS_INT(id) && JSID_TO_INT(id) >= 0)
                       ? JSVAL_NULL
                       : JSVAL_VOID;
 #else
@@ -2739,7 +3161,7 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
      * Handle old bug that took empty string as zero index.  Also convert
      * string indices to integers if appropriate.
      */
-    CHECK_FOR_FUNNY_INDEX(id);
+    CHECK_FOR_STRING_INDEX(id);
 
     if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
         return JS_FALSE;
@@ -2777,7 +3199,7 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
         if ((attrs & JSPROP_READONLY) ||
             (SCOPE_IS_SEALED(scope) && pobj == obj)) {
             JS_UNLOCK_SCOPE(cx, scope);
-            if ((attrs & JSPROP_READONLY) && JSVERSION_IS_ECMA(cx->version))
+            if ((attrs & JSPROP_READONLY) && JS_VERSION_IS_ECMA(cx))
                 return JS_TRUE;
             goto read_only_error;
         }
@@ -2844,17 +3266,20 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
             return JS_FALSE;
         }
 
-        /* XXXbe called with obj locked */
-        if (!clasp->addProperty(cx, obj, SPROP_USERID(sprop), vp)) {
-            (void) js_RemoveScopeProperty(cx, scope, id);
-            JS_UNLOCK_SCOPE(cx, scope);
-            return JS_FALSE;
-        }
-
-        /* Initialize new property value (passed to setter) to undefined. */
+        /*
+         * 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);
     }
 
@@ -2954,9 +3379,7 @@ js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
         }
     }
     sprop = (JSScopeProperty *)prop;
-    sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,
-                                         *attrsp &
-                                         ~(JSPROP_GETTER | JSPROP_SETTER), 0,
+    sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, *attrsp, 0,
                                          sprop->getter, sprop->setter);
     if (noprop)
         OBJ_DROP_PROPERTY(cx, obj, prop);
@@ -2975,13 +3398,13 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
     JSScope *scope;
     JSBool ok;
 
-    *rval = JSVERSION_IS_ECMA(cx->version) ? JSVAL_TRUE : JSVAL_VOID;
+    *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_FUNNY_INDEX(id);
+    CHECK_FOR_STRING_INDEX(id);
 
     if (!js_LookupProperty(cx, obj, id, &proto, &prop))
         return JS_FALSE;
@@ -3015,7 +3438,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
     sprop = (JSScopeProperty *)prop;
     if (sprop->attrs & JSPROP_PERMANENT) {
         OBJ_DROP_PROPERTY(cx, obj, prop);
-        if (JSVERSION_IS_ECMA(cx->version)) {
+        if (JS_VERSION_IS_ECMA(cx)) {
             *rval = JSVAL_FALSE;
             return JS_TRUE;
         }
@@ -3068,8 +3491,9 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
          * method, and calling that method returned failure.
          */
         if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL,
-                          &v))
+                          &v)) {
             return JS_FALSE;
+        }
 
         if (!JSVAL_IS_PRIMITIVE(v)) {
             if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, hint, &v))
@@ -3080,7 +3504,7 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
              * object to a string.  ECMA requires an error if both toString
              * and valueOf fail to produce a primitive value.
              */
-            if (!JSVAL_IS_PRIMITIVE(v) && cx->version == JSVERSION_1_2) {
+            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)
@@ -3106,7 +3530,7 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
                 goto out;
             }
             /* Don't convert to string (source object literal) for JS1.2. */
-            if (cx->version == JSVERSION_1_2 && hint == JSTYPE_BOOLEAN)
+            if (JS_VERSION_IS_1_2(cx) && hint == JSTYPE_BOOLEAN)
                 goto out;
             if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0,
                               NULL, &v))
@@ -3146,27 +3570,33 @@ js_NewIdArray(JSContext *cx, jsint length)
     JSIdArray *ida;
 
     ida = (JSIdArray *)
-        JS_malloc(cx, sizeof(JSIdArray) + (length - 1) * sizeof(jsval));
+          JS_malloc(cx, sizeof(JSIdArray) + (length-1) * sizeof(jsval));
     if (ida)
         ida->length = length;
     return ida;
 }
 
 JSIdArray *
-js_GrowIdArray(JSContext *cx, JSIdArray *ida, jsint length)
+js_SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
 {
-    ida = (JSIdArray *)
-        JS_realloc(cx, ida, sizeof(JSIdArray) + (length - 1) * sizeof(jsval));
-    if (ida)
-        ida->length = length;
-    return ida;
+    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 */
-typedef struct JSNativeIteratorState {
-    jsint next_index;   /* index into jsid array */
-    JSIdArray *ida;     /* All property ids in enumeration */
-} JSNativeIteratorState;
+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
@@ -3177,7 +3607,8 @@ JSBool
 js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
              jsval *statep, jsid *idp)
 {
-    JSObject *proto_obj;
+    JSRuntime *rt;
+    JSObject *proto;
     JSClass *clasp;
     JSEnumerateOp enumerate;
     JSScopeProperty *sprop, *lastProp;
@@ -3186,16 +3617,16 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
     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:
+      case JSENUMERATE_INIT:
         if (!enumerate(cx, obj))
-            goto init_error;
+            return JS_FALSE;
         length = 0;
 
         /*
@@ -3211,12 +3642,12 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
          * its properties.  Otherwise they will be enumerated a second time
          * when the prototype object is enumerated.
          */
-        proto_obj = OBJ_GET_PROTO(cx, obj);
-        if (proto_obj && scope == OBJ_SCOPE(proto_obj)) {
+        proto = OBJ_GET_PROTO(cx, obj);
+        if (proto && scope == OBJ_SCOPE(proto)) {
             ida = js_NewIdArray(cx, 0);
             if (!ida) {
                 JS_UNLOCK_OBJ(cx, obj);
-                goto init_error;
+                return JS_FALSE;
             }
         } else {
             /* Object has a private scope; Enumerate all props in scope. */
@@ -3236,7 +3667,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
             ida = js_NewIdArray(cx, length);
             if (!ida) {
                 JS_UNLOCK_OBJ(cx, obj);
-                goto init_error;
+                return JS_FALSE;
             }
             i = length;
             for (sprop = lastProp; sprop; sprop = sprop->parent) {
@@ -3259,81 +3690,151 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
             JS_malloc(cx, sizeof(JSNativeIteratorState));
         if (!state) {
             JS_DestroyIdArray(cx, ida);
-            goto init_error;
+            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);
-        return JS_TRUE;
+        break;
 
-    case JSENUMERATE_NEXT:
+      case JSENUMERATE_NEXT:
         state = (JSNativeIteratorState *) JSVAL_TO_PRIVATE(*statep);
         ida = state->ida;
         length = ida->length;
         if (state->next_index != length) {
             *idp = ida->vector[state->next_index++];
-            return JS_TRUE;
+            break;
         }
+        /* FALL THROUGH */
 
-        /* Fall through ... */
-
-    case JSENUMERATE_DESTROY:
+      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;
-        return JS_TRUE;
-
-    default:
-        JS_ASSERT(0);
-        return JS_FALSE;
+        break;
     }
+    return JS_TRUE;
+}
 
-init_error:
-    *statep = JSVAL_NULL;
-    return JS_FALSE;
+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;
-    JSScopeProperty *sprop;
     JSClass *clasp;
-    JSBool ok;
+    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;
 
-    if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
-        return JS_FALSE;
-    if (!prop) {
-        *vp = JSVAL_VOID;
-        *attrsp = 0;
-        clasp = OBJ_GET_CLASS(cx, obj);
-        return !clasp->checkAccess ||
-               clasp->checkAccess(cx, obj, ID_TO_VALUE(id), mode, vp);
-    }
-    if (!OBJ_IS_NATIVE(pobj)) {
+      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);
-        return OBJ_CHECK_ACCESS(cx, pobj, id, mode, vp, attrsp);
     }
-    sprop = (JSScopeProperty *)prop;
-    *vp = (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)))
-          ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
-          : JSVAL_VOID;
-    *attrsp = sprop->attrs;
-    clasp = LOCKED_OBJ_GET_CLASS(obj);
-    if (clasp->checkAccess) {
-        JS_UNLOCK_OBJ(cx, pobj);
-        ok = clasp->checkAccess(cx, obj, ID_TO_VALUE(id), mode, vp);
-        JS_LOCK_OBJ(cx, pobj);
-    } else {
-        ok = JS_TRUE;
-    }
-    OBJ_DROP_PROPERTY(cx, pobj, prop);
-    return ok;
+
+    /*
+     * 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
@@ -3382,7 +3883,8 @@ GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval)
     while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
         obj = tmp;
     if (!OBJ_GET_PROPERTY(cx, obj,
-                          (jsid)cx->runtime->atomState.ExecutionContextAtom,
+                          ATOM_TO_JSID(cx->runtime->atomState
+                                       .ExecutionContextAtom),
                           &xcval)) {
         return JS_FALSE;
     }
@@ -3391,7 +3893,7 @@ GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval)
         return JS_FALSE;
     }
     if (!OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(xcval),
-                          (jsid)cx->runtime->atomState.currentAtom,
+                          ATOM_TO_JSID(cx->runtime->atomState.currentAtom),
                           rval)) {
         return JS_FALSE;
     }
@@ -3413,7 +3915,7 @@ js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
         callee = JSVAL_TO_OBJECT(argv[-2]);
         if (!OBJ_GET_PROPERTY(cx, callee,
-                              (jsid)cx->runtime->atomState.callAtom,
+                              ATOM_TO_JSID(cx->runtime->atomState.callAtom),
                               &fval)) {
             return JS_FALSE;
         }
@@ -3455,7 +3957,8 @@ js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
         callee = JSVAL_TO_OBJECT(argv[-2]);
         if (!OBJ_GET_PROPERTY(cx, callee,
-                              (jsid)cx->runtime->atomState.constructAtom,
+                              ATOM_TO_JSID(cx->runtime->atomState
+                                           .constructAtom),
                               &cval)) {
             return JS_FALSE;
         }
@@ -3485,6 +3988,7 @@ JSBool
 js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
 {
     JSClass *clasp;
+    JSString *str;
 
     clasp = OBJ_GET_CLASS(cx, obj);
     if (clasp->hasInstance)
@@ -3494,7 +3998,8 @@ js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
         jsval fval, rval;
 
         if (!OBJ_GET_PROPERTY(cx, obj,
-                              (jsid)cx->runtime->atomState.hasInstanceAtom,
+                              ATOM_TO_JSID(cx->runtime->atomState
+                                           .hasInstanceAtom),
                               &fval)) {
             return JS_FALSE;
         }
@@ -3504,8 +4009,14 @@ js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
         }
     }
 #endif
-    *bp = JS_FALSE;
-    return JS_TRUE;
+    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
@@ -3539,20 +4050,72 @@ GetClassPrototype(JSContext *cx, JSObject *scope, const char *name,
     jsval v;
     JSObject *ctor;
 
-    if (!FindConstructor(cx, scope, name, &v))
+    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,
-                              (jsid)cx->runtime->atomState.classPrototypeAtom,
+                              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)
@@ -3564,8 +4127,10 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto,
      * DontDelete.
      */
     if (!OBJ_DEFINE_PROPERTY(cx, ctor,
-                             (jsid)cx->runtime->atomState.classPrototypeAtom,
-                             OBJECT_TO_JSVAL(proto), NULL, NULL,
+                             ATOM_TO_JSID(cx->runtime->atomState
+                                          .classPrototypeAtom),
+                             OBJECT_TO_JSVAL(proto),
+                             JS_PropertyStub, JS_PropertyStub,
                              attrs, NULL)) {
         return JS_FALSE;
     }
@@ -3575,8 +4140,10 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto,
      * for a user-defined function f, is DontEnum.
      */
     return OBJ_DEFINE_PROPERTY(cx, proto,
-                               (jsid)cx->runtime->atomState.constructorAtom,
-                               OBJECT_TO_JSVAL(ctor), NULL, NULL,
+                               ATOM_TO_JSID(cx->runtime->atomState
+                                            .constructorAtom),
+                               OBJECT_TO_JSVAL(ctor),
+                               CheckCtorGetAccess, CheckCtorSetAccess,
                                0, NULL);
 }
 
@@ -3649,8 +4216,15 @@ 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
@@ -3658,16 +4232,24 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
      * behave properly.
      */
     older = JS_SetErrorReporter(cx, NULL);
-    if (!OBJ_GET_PROPERTY(cx, obj, (jsid)atom, &fval)) {
-        JS_ClearPendingException(cx);
-        ok = JS_TRUE;
-    } else if (!JSVAL_IS_PRIMITIVE(fval)) {
-        ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
-        if (!ok)
-            JS_ClearPendingException(cx);
-    } else {
-        ok = JS_TRUE;
+    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;
 }
@@ -3713,7 +4295,7 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp)
 
     if (xdr->mode != JSXDR_ENCODE) {
         if (classDef) {
-            ok = js_GetClassPrototype(cx, className, &proto);
+            ok = GetClassPrototype(cx, NULL, className, &proto);
             if (!ok)
                 goto out;
             clasp = OBJ_GET_CLASS(cx, proto);
@@ -3834,14 +4416,16 @@ js_Mark(JSContext *cx, JSObject *obj, void *arg)
         if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
             continue;
         MARK_SCOPE_PROPERTY(sprop);
-        if (!JSVAL_IS_INT(sprop->id))
-            GC_MARK_ATOM(cx, (JSAtom *)sprop->id, arg);
+        if (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 = (JSAtom *)sprop->id;
+            JSAtom *atom = JSID_TO_ATOM(sprop->id);
             const char *id = (atom && ATOM_IS_STRING(atom))
                              ? JS_GetStringBytes(ATOM_TO_STRING(atom))
                              : "unknown";
@@ -3941,7 +4525,7 @@ JSBool
 js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
 {
     JSScope *scope;
-    uint32 nslots, i;
+    uint32 nslots;
     JSClass *clasp;
     jsval *newslots;
 
@@ -3966,18 +4550,14 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
             nslots += clasp->reserveSlots(cx, obj);
         JS_ASSERT(slot < nslots);
 
-        newslots = (jsval *)
-            JS_realloc(cx, obj->slots - 1, (nslots + 1) * sizeof(jsval));
+        newslots = AllocSlots(cx, obj->slots, nslots);
         if (!newslots) {
             JS_UNLOCK_SCOPE(cx, scope);
             return JS_FALSE;
         }
-        for (i = 1 + newslots[0]; i <= nslots; i++)
-            newslots[i] = JSVAL_VOID;
         if (scope->object == obj)
             scope->map.nslots = nslots;
-        newslots[0] = nslots;
-        obj->slots = newslots + 1;
+        obj->slots = newslots;
     }
 
     /* Whether or not we grew nslots, we may need to advance freeslot. */
index 9ac5857e0978b7b821fa35e1c6bd04a6485c11f7..a2400e982316705e8164a3abed9c0965875ddff5 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
@@ -61,13 +62,8 @@ struct JSObjectMap {
 };
 
 /* Shorthand macros for frequently-made calls. */
-#if defined JS_THREADSAFE && defined DEBUG
-#define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp)                             \
-    (obj)->map->ops->lookupProperty(cx,obj,id,objp,propp,__FILE__,__LINE__)
-#else
 #define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp)                             \
     (obj)->map->ops->lookupProperty(cx,obj,id,objp,propp)
-#endif
 #define OBJ_DEFINE_PROPERTY(cx,obj,id,value,getter,setter,attrs,propp)        \
     (obj)->map->ops->defineProperty(cx,obj,id,value,getter,setter,attrs,propp)
 #define OBJ_GET_PROPERTY(cx,obj,id,vp)                                        \
@@ -105,6 +101,16 @@ struct JSObjectMap {
      ? (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,
@@ -231,6 +237,24 @@ 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;
@@ -240,26 +264,37 @@ struct JSSharpObjectMap {
 #define SHARP_BIT       ((jsatomid) 1)
 #define BUSY_BIT        ((jsatomid) 2)
 #define SHARP_ID_SHIFT  2
-#define IS_SHARP(he)    ((jsatomid)(he)->value & SHARP_BIT)
-#define MAKE_SHARP(he)  ((he)->value = (void*)((jsatomid)(he)->value|SHARP_BIT))
-#define IS_BUSY(he)     ((jsatomid)(he)->value & BUSY_BIT)
-#define MAKE_BUSY(he)   ((he)->value = (void*)((jsatomid)(he)->value|BUSY_BIT))
-#define CLEAR_BUSY(he)  ((he)->value = (void*)((jsatomid)(he)->value&~BUSY_BIT))
+#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);
+                    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);
+                jsval *rval);
 
 extern JSBool
 js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-               jsval *rval);
+                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);
@@ -277,11 +312,11 @@ extern const char js_lookupSetter_str[];
 
 extern void
 js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
-                JSClass *clasp);
+                 JSClass *clasp);
 
 extern JSObjectMap *
 js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
-               JSClass *clasp, JSObject *obj);
+                JSClass *clasp, JSObject *obj);
 
 extern void
 js_DestroyObjectMap(JSContext *cx, JSObjectMap *map);
@@ -295,6 +330,9 @@ 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);
@@ -308,6 +346,21 @@ 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.
@@ -336,8 +389,8 @@ js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
  */
 extern JSBool
 js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
-                 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
-                 JSProperty **propp);
+                  JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+                  JSProperty **propp);
 
 extern JSBool
 js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
@@ -351,33 +404,20 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
  * *objp and *propp null.  Therefore all callers who receive a non-null *propp
  * must later call OBJ_DROP_PROPERTY(cx, *objp, *propp).
  */
-#if defined JS_THREADSAFE && defined DEBUG
-extern JS_FRIEND_API(JSBool)
-_js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
-                  JSProperty **propp, const char *file, uintN line);
-
-#define js_LookupProperty(cx,obj,id,objp,propp) \
-    _js_LookupProperty(cx,obj,id,objp,propp,__FILE__,__LINE__)
-#else
 extern JS_FRIEND_API(JSBool)
 js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
-                 JSProperty **propp);
-#endif
+                  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
-#if defined JS_THREADSAFE && defined DEBUG
-                           , const char *file, uintN line
-#endif
-                           );
+                           JSObject **objp, JSProperty **propp);
 
 extern JS_FRIEND_API(JSBool)
 js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
-               JSProperty **propp);
+                JSProperty **propp);
 
 extern JSObject *
 js_FindIdentifierBase(JSContext *cx, jsid id);
@@ -393,11 +433,11 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
 
 extern JSBool
 js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
-                uintN *attrsp);
+                 uintN *attrsp);
 
 extern JSBool
 js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
-                uintN *attrsp);
+                 uintN *attrsp);
 
 extern JSBool
 js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval);
@@ -408,23 +448,29 @@ 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_GrowIdArray(JSContext *cx, JSIdArray *ida, jsint length);
+js_SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length);
 
 extern JSBool
 js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
-            jsval *statep, jsid *idp);
+             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);
+               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);
+             jsval *rval);
 
 extern JSBool
 js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
@@ -440,7 +486,7 @@ js_GetClassPrototype(JSContext *cx, const char *name, JSObject **protop);
 
 extern JSBool
 js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto,
-                    uintN attrs);
+                     uintN attrs);
 
 extern JSBool
 js_ValueToObject(JSContext *cx, jsval v, JSObject **objp);
@@ -453,7 +499,7 @@ 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);
+             uintN argc, jsval *argv, jsval *rval);
 
 extern JSBool
 js_XDRObject(JSXDRState *xdr, JSObject **objp);
@@ -470,6 +516,12 @@ 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___ */
index e751103a0fd4f25b2df4e74dcf504d7d9496d544..80c7eb4dd0bd794352b2cdc236862e2ac7582e62 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
@@ -82,6 +83,7 @@ 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[]      = {"++", "--"};
 
@@ -111,7 +113,7 @@ 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);
@@ -120,7 +122,7 @@ GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
 
 #ifdef DEBUG
 
-JS_FRIEND_API(void)
+JS_FRIEND_API(JSBool)
 js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
 {
     jsbytecode *pc, *end;
@@ -135,9 +137,10 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
                               PTRDIFF(pc, script->code, jsbytecode),
                               lines, fp);
         if (!len)
-            return;
+            return JS_FALSE;
         pc += len;
     }
+    return JS_TRUE;
 }
 
 JS_FRIEND_API(uintN)
@@ -150,7 +153,6 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
     uint32 type;
     JSAtom *atom;
     JSString *str;
-    char *cstr;
 
     op = (JSOp)*pc;
     if (op >= JSOP_LIMIT) {
@@ -189,11 +191,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
         str = js_ValueToSource(cx, ATOM_KEY(atom));
         if (!str)
             return 0;
-        cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
-        if (!cstr)
-            return 0;
-        fprintf(fp, " %s", cstr);
-        JS_free(cx, cstr);
+        fprintf(fp, " %s", JS_GetStringBytes(str));
         break;
 
       case JOF_UINT16:
@@ -249,12 +247,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
             str = js_ValueToSource(cx, ATOM_KEY(atom));
             if (!str)
                 return 0;
-            cstr = js_DeflateString(cx, JSSTRING_CHARS(str),
-                                    JSSTRING_LENGTH(str));
-            if (!cstr)
-                return 0;
-            fprintf(fp, "\n\t%s: %d", cstr, off);
-            JS_free(cx, cstr);
+            fprintf(fp, "\n\t%s: %d", JS_GetStringBytes(str), off);
             npairs--;
         }
         len = 1 + pc2 - pc;
@@ -271,21 +264,59 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
         break;
 
 #if JS_HAS_LEXICAL_CLOSURE
-      case JOF_DEFLOCALVAR:
+      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;
-        cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
-        if (!cstr)
-            return 0;
-        fprintf(fp, " %s", cstr);
-        JS_free(cx, cstr);
+        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 <uint24> op [<varno> 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,
+         * <varno> 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);
@@ -365,7 +396,7 @@ Sprint(Sprinter *sp, const char *format, ...)
     ptrdiff_t offset;
 
     va_start(ap, format);
-    bp = JS_vsmprintf(format, ap);     /* XXX vsaprintf */
+    bp = JS_vsmprintf(format, ap);      /* XXX vsaprintf */
     va_end(ap);
     if (!bp) {
         JS_ReportOutOfMemory(sp->context);
@@ -432,10 +463,36 @@ QuoteString(Sprinter *sp, JSString *str, jschar quote)
             break;
 
         /* Use js_EscapeMap, \u, or \x only if necessary. */
-        if ((u = js_strchr(js_EscapeMap, c)) != NULL)
+        if ((u = js_strchr(js_EscapeMap, c)) != NULL) {
             ok = Sprint(sp, "\\%c", (char)u[1]) >= 0;
-        else
+        } 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;
     }
@@ -443,6 +500,13 @@ QuoteString(Sprinter *sp, JSString *str, jschar quote)
     /* 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);
 }
 
@@ -545,7 +609,7 @@ js_printf(JSPrinter *jp, const char *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') {
+    if (!jp->pretty && format[cc = strlen(format) - 1] == '\n') {
         fp = JS_strdup(jp->sprinter.context, format);
         if (!fp)
             return -1;
@@ -554,7 +618,7 @@ js_printf(JSPrinter *jp, const char *format, ...)
     }
 
     /* Allocate temp space, convert format, and put. */
-    bp = JS_vsmprintf(format, ap);     /* XXX vsaprintf */
+    bp = JS_vsmprintf(format, ap);      /* XXX vsaprintf */
     if (fp) {
         JS_free(jp->sprinter.context, fp);
         format = NULL;
@@ -590,7 +654,7 @@ typedef struct SprintStack {
 } SprintStack;
 
 /* Gap between stacked strings to allow for insertion of parens and commas. */
-#define PAREN_SLOP     (2 + 1)
+#define PAREN_SLOP      (2 + 1)
 
 /*
  * These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETNAME,
@@ -701,7 +765,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
         diff = table[0].offset - defaultOffset;
         if (diff > 0) {
             jp->indent += 2;
-            js_printf(jp, "\tdefault:\n");
+            js_printf(jp, "\t%s:\n", js_default_str);
             jp->indent += 2;
             if (!Decompile(ss, pc + defaultOffset, diff))
                 return JS_FALSE;
@@ -751,7 +815,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
                         return JS_FALSE;
                 }
                 rval = QuoteString(&ss->sprinter, str,
-                                   JSVAL_IS_STRING(key) ? (jschar)'"' : 0);
+                                   (jschar)(JSVAL_IS_STRING(key) ? '"' : 0));
                 if (!rval)
                     return JS_FALSE;
                 RETRACT(&ss->sprinter, rval);
@@ -768,7 +832,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
                     off = defaultOffset;
                 }
                 jp->indent -= 2;
-                js_printf(jp, "\tdefault:\n");
+                js_printf(jp, "\t%s:\n", js_default_str);
                 jp->indent += 2;
             }
             if (!Decompile(ss, pc + off, off2 - off))
@@ -779,7 +843,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
 
     if (defaultOffset == switchLength) {
         jp->indent += 2;
-        js_printf(jp, "\tdefault:;\n");
+        js_printf(jp, "\t%s:;\n", js_default_str);
         jp->indent -= 2;
     }
     js_printf(jp, "\t}\n");
@@ -800,9 +864,9 @@ GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot)
             if (sprop->getter != getter)
                 continue;
             JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
-            JS_ASSERT(!JSVAL_IS_INT(sprop->id));
+            JS_ASSERT(JSID_IS_ATOM(sprop->id));
             if ((uintN) sprop->shortid == slot)
-                return (JSAtom *) sprop->id;
+                return JSID_TO_ATOM(sprop->id);
         }
         obj = scope->object;
         if (!obj)
@@ -818,20 +882,13 @@ GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot)
 static const char *
 VarPrefix(jssrcnote *sn)
 {
-    const char *kw;
-    static char buf[8];
-
-    kw = NULL;
     if (sn) {
         if (SN_TYPE(sn) == SRC_VAR)
-            kw = js_var_str;
-        else if (SN_TYPE(sn) == SRC_CONST)
-            kw = js_const_str;
+            return "var ";
+        if (SN_TYPE(sn) == SRC_CONST)
+            return "const ";
     }
-    if (!kw)
-        return "";
-    JS_snprintf(buf, sizeof buf, "%s ", kw);
-    return buf;
+    return "";
 }
 
 static JSBool
@@ -847,21 +904,28 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
     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
+#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
@@ -871,13 +935,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
     (!ATOM_KEYWORD(atom) && js_IsIdentifier(ATOM_TO_STRING(atom)))
 
 /*
- * Get atom from script's atom map, quote/escape its string appropriately into
- * rval, and select fmt from the quoted and unquoted alternatives.
+ * 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_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval)                              \
+#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval)                                   \
     JS_BEGIN_MACRO                                                            \
         jschar quote_;                                                        \
-        atom = GET_ATOM(cx, jp->script, pc);                                  \
         if (!ATOM_IS_IDENTIFIER(atom)) {                                      \
             quote_ = '\'';                                                    \
             fmt = qfmt;                                                       \
@@ -890,15 +954,33 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
             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. */
+    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;
@@ -926,9 +1008,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {
                     /* Print only the right operand of the assignment-op. */
                     todo = SprintPut(&ss->sprinter, rval, strlen(rval));
-                } else {
+                } 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;
 
@@ -938,12 +1024,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 break;
 
               case 0:
-#if JS_HAS_GETTER_SETTER
-                if (op == JSOP_GETTER || op == JSOP_SETTER) {
-                    todo = -2;
-                    break;
-                }
-#endif
                 todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token));
                 break;
 
@@ -953,6 +1033,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
             }
         } 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
@@ -1054,14 +1143,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                     pc += js_CodeSpec[JSOP_NEWINIT].length;
                     LOCAL_ASSERT(*pc == JSOP_EXCEPTION);
                     pc += js_CodeSpec[JSOP_EXCEPTION].length;
-                    LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR);
-                    atom = GET_ATOM(cx, jp->script, pc);
+                    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);
-                    pc += js_CodeSpec[JSOP_INITCATCHVAR].length;
                     LOCAL_ASSERT(*pc == JSOP_ENTERWITH);
                     pc += js_CodeSpec[JSOP_ENTERWITH].length;
 
@@ -1093,12 +1190,20 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                     if (!jp2)
                         return JS_FALSE;
                     jp2->scope = jp->scope;
-                    if (js_DecompileFunction(jp2, fun)) {
+                    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:;
@@ -1122,6 +1227,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
               case JSOP_PUSH:
               case JSOP_PUSHOBJ:
               case JSOP_BINDNAME:
+              do_JSOP_BINDNAME:
                 todo = Sprint(&ss->sprinter, "");
                 break;
 
@@ -1133,7 +1239,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 break;
 
             {
-              static const char finally_cookie[] = "/*FINALLY*/";
+              static const char exception_cookie[] = "/*EXCEPTION*/";
+              static const char retsub_pc_cookie[] = "/*RETSUB_PC*/";
 
               case JSOP_FINALLY:
                 jp->indent -= 4;
@@ -1145,12 +1252,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                  * address, popped by JSOP_RETSUB and counted by script->depth
                  * but not by ss->top (see JSOP_SETSP, below).
                  */
-                todo = Sprint(&ss->sprinter, finally_cookie);
+                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, finally_cookie) == 0);
+                LOCAL_ASSERT(strcmp(rval, retsub_pc_cookie) == 0);
+                lval = POP_STR();
+                LOCAL_ASSERT(strcmp(lval, exception_cookie) == 0);
                 todo = -2;
                 break;
             }
@@ -1285,6 +1397,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 break;
 
 #if JS_HAS_EXCEPTIONS
+              case JSOP_THROWING:
+                todo = -2;
+                break;
+
               case JSOP_THROW:
                 sn = js_GetSrcNote(jp->script, pc);
                 todo = -2;
@@ -1489,15 +1605,26 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 tail = js_GetSrcNoteOffset(sn2, 0);
 
               do_forinbody:
-                js_printf(jp, "\tfor (%s%s", VarPrefix(sn), lval);
+#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) {
-                    js_printf(jp, "[%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);
@@ -1559,6 +1686,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 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));
@@ -1585,7 +1719,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
               case JSOP_SETCONST:
               case JSOP_SETNAME:
               case JSOP_SETGVAR:
-                atom = GET_ATOM(cx, jp->script, pc);
+                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)
@@ -1593,6 +1731,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 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) {
@@ -1694,10 +1833,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
               case JSOP_DELELEM:
                 xval = POP_STR();
                 lval = POP_STR();
-                todo = Sprint(&ss->sprinter, "%s %s[%s]",
+                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();
@@ -1743,9 +1894,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
               case JSOP_DECELEM:
                 xval = POP_STR();
                 lval = POP_STR();
-                todo = Sprint(&ss->sprinter, "%s%s[%s]",
-                              js_incop_str[!(cs->format & JOF_INC)],
-                              lval, xval);
+                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:
@@ -1787,9 +1946,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
               case JSOP_ELEMDEC:
                 xval = POP_STR();
                 lval = POP_STR();
-                todo = Sprint(&ss->sprinter, "%s[%s]%s",
-                              lval, xval,
-                              js_incop_str[!(cs->format & JOF_INC)]);
+                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:
@@ -1798,13 +1965,41 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 /* FALL THROUGH */
 
               case JSOP_GETPROP:
-                GET_ATOM_QUOTE_AND_FMT("%s[%s]", "%s.%s", rval);
+                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:
-                GET_ATOM_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval);
+                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);
@@ -1825,10 +2020,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 xval = POP_STR();
                 op = JSOP_GETELEM;
                 lval = POP_STR();
-                if (*xval == '\0')
+                if (*xval == '\0') {
                     todo = Sprint(&ss->sprinter, "%s", lval);
-                else
-                    todo = Sprint(&ss->sprinter, "%s[%s]", lval, xval);
+                } else {
+                    todo = Sprint(&ss->sprinter,
+                                  (js_CodeSpec[lastop].format & JOF_XMLNAME)
+                                  ? "%s.%s"
+                                  : "%s[%s]",
+                                  lval, xval);
+                }
                 break;
 
               case JSOP_SETELEM:
@@ -1840,7 +2040,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 if (*xval == '\0')
                     goto do_setlval;
                 sn = js_GetSrcNote(jp->script, pc - 1);
-                todo = Sprint(&ss->sprinter, "%s[%s] %s= %s",
+                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
@@ -1883,11 +2086,62 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
 
               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_NUMBER:
-                atom = GET_ATOM(cx, jp->script, pc);
+              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);
@@ -1902,22 +2156,27 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                     }
                     todo = Sprint(&ss->sprinter, numStr);
                 }
-                break;
+              END_LITOPX_CASE
 
-              case JSOP_STRING:
-                atom = GET_ATOM(cx, jp->script, pc);
+              BEGIN_LITOPX_CASE(JSOP_STRING)
                 rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
-                                   (jschar)'"');
+                                   inXML ? 0 : (jschar)'"');
                 if (!rval)
                     return JS_FALSE;
                 todo = STR2OFF(&ss->sprinter, rval);
-                break;
+              END_LITOPX_CASE
 
               case JSOP_OBJECT:
               case JSOP_REGEXP:
               case JSOP_ANONFUNOBJ:
               case JSOP_NAMEDFUNOBJ:
-                atom = GET_ATOM(cx, jp->script, pc);
+                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)) {
@@ -1946,7 +2205,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 jsbytecode *pc2;
                 ptrdiff_t jmplen, off, off2;
                 jsint j, n, low, high;
-                TableEntry *table;
+                TableEntry *table, pivot;
 
                 sn = js_GetSrcNote(jp->script, pc);
                 JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
@@ -1989,7 +2248,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                         }
                         pc2 += jmplen;
                     }
-                    js_HeapSort(table, (size_t) j, sizeof(TableEntry),
+                    js_HeapSort(table, (size_t) j, &pivot, sizeof(TableEntry),
                                 CompareOffsets, NULL);
                 }
 
@@ -2149,19 +2408,20 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                               lval,
                               (op == JSOP_NEW_EQ) ? '=' : '!',
 #if JS_HAS_TRIPLE_EQOPS
-                              JSVERSION_IS_ECMA(cx->version) ? "==" :
+                              JS_VERSION_IS_ECMA(cx) ? "==" :
 #endif
                               "=",
                               rval);
                 break;
-#endif /* !JS_BUG_FALLIBLE_EQOPS */
+#endif
 
 #if JS_HAS_LEXICAL_CLOSURE
-              case JSOP_CLOSURE:
-                atom = GET_ATOM(cx, jp->script, pc);
+              BEGIN_LITOPX_CASE(JSOP_CLOSURE)
                 JS_ASSERT(ATOM_IS_OBJECT(atom));
+                todo = -2;
                 goto do_function;
-#endif /* JS_HAS_LEXICAL_CLOSURE */
+              END_LITOPX_CASE
+#endif
 
 #if JS_HAS_EXPORT_IMPORT
               case JSOP_EXPORTALL:
@@ -2169,15 +2429,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 todo = -2;
                 break;
 
-              case JSOP_EXPORTNAME:
-                atom = GET_ATOM(cx, jp->script, pc);
+              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;
-                break;
+              END_LITOPX_CASE
 
               case JSOP_IMPORTALL:
                 lval = POP_STR();
@@ -2186,6 +2445,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 break;
 
               case JSOP_IMPORTPROP:
+              do_importprop:
                 GET_ATOM_QUOTE_AND_FMT("\timport %s[%s]\n", "\timport %s.%s\n",
                                        rval);
                 lval = POP_STR();
@@ -2196,6 +2456,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
               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;
@@ -2246,10 +2508,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 break;
 
               case JSOP_INITPROP:
-              case JSOP_INITCATCHVAR:
                 atom = GET_ATOM(cx, jp->script, pc);
                 xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
-                                   ATOM_IS_IDENTIFIER(atom) ? 0 : '\'');
+                                   (jschar)
+                                   (ATOM_IS_IDENTIFIER(atom) ? 0 : '\''));
                 if (!xval)
                     return JS_FALSE;
                 rval = POP_STR();
@@ -2268,13 +2530,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                               rval);
 #else
                 if (lastop == JSOP_GETTER || lastop == JSOP_SETTER) {
-                    todo = Sprint(&ss->sprinter, "%s%s%s %s%s",
+                    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,
-                                  rval + strlen(js_function_str) + 1);
+                                  strlen(rval) - 1,
+                                  rval);
                 } else {
                     todo = Sprint(&ss->sprinter, "%s%s%s:%s",
                                   lval,
@@ -2319,9 +2583,166 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
                 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, "<xml address='%p'>",
+                              ATOM_TO_OBJECT(atom));
+              END_LITOPX_CASE
+
+              BEGIN_LITOPX_CASE(JSOP_XMLCDATA)
+                todo = SprintPut(&ss->sprinter, "<![CDATA[", 9);
+                if (!QuoteString(&ss->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, "<!--", 4);
+                if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0))
+                    return JS_FALSE;
+                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, "<?", 2);
+                ok = QuoteString(&ss->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
             }
         }
 
@@ -2339,10 +2760,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
 /*
  * 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;
@@ -2443,7 +2866,6 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
      * an expression by parenthesizing.
      */
     if (jp->pretty) {
-        js_puts(jp, "\n");
         js_printf(jp, "\t");
     } else {
         if (!jp->grouped && (fun->flags & JSFUN_LAMBDA))
@@ -2460,6 +2882,8 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
     js_puts(jp, "(");
 
     if (fun->interpreted && fun->object) {
+        size_t paramsize;
+
         /*
          * Print the parameters.
          *
@@ -2473,20 +2897,21 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
         cx = jp->sprinter.context;
         nargs = fun->nargs;
         mark = JS_ARENA_MARK(&cx->tempPool);
-        JS_ARENA_ALLOCATE_CAST(params, JSAtom **, &cx->tempPool,
-                               nargs * sizeof(JSAtom *));
+        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((uintN) sprop->shortid < nargs);
-            JS_ASSERT(!JSVAL_IS_INT(sprop->id));
-            params[(uintN) sprop->shortid] = (JSAtom *) sprop->id;
+            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)
@@ -2519,9 +2944,7 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
     jp->indent -= 4;
     js_printf(jp, "\t}");
 
-    if (jp->pretty) {
-        js_puts(jp, "\n");
-    } else {
+    if (!jp->pretty) {
         if (!jp->grouped && (fun->flags & JSFUN_LAMBDA))
             js_puts(jp, ")");
     }
@@ -2538,14 +2961,15 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
     JSScript *script;
     JSOp op;
     const JSCodeSpec *cs;
-    uint32 format, mode;
+    uint32 format, mode, type;
     intN depth;
     jssrcnote *sn;
     uintN len, off;
     JSPrinter *jp;
     JSString *name;
 
-    fp = cx->fp;
+    for (fp = cx->fp; fp && !fp->script; fp = fp->down)
+        continue;
     if (!fp)
         goto do_fallback;
 
@@ -2657,8 +3081,11 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
         begin = pc;
     } else {
         sn = js_GetSrcNote(script, pc);
-        if (!sn || SN_TYPE(sn) != SRC_PCBASE)
+        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;
@@ -2670,7 +3097,17 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
             return NULL;
         memcpy(tmp, begin, len * sizeof(jsbytecode));
         if (mode == JOF_NAME) {
-            tmp[0] = JSOP_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
@@ -2719,8 +3156,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
         }
         if (js_DecompileCode(jp, script, begin, len))
             name = js_GetPrinterOutput(jp);
+        js_DestroyPrinter(jp);
     }
-    js_DestroyPrinter(jp);
     if (tmp)
         JS_free(cx, tmp);
     return name;
index 01a6d46ac7905da0e12887495c1ee27edecc76bc..2a488f6eb66df2f7547c8d2d2ec5bbaa3ee8f2ce 100644 (file)
@@ -70,10 +70,14 @@ typedef enum JSOp {
 #define JOF_LOOKUPSWITCH  5       /* lookup switch */
 #define JOF_QARG          6       /* quickened get/set function argument ops */
 #define JOF_QVAR          7       /* quickened get/set local variable ops */
-#define JOF_DEFLOCALVAR   8       /* define local var with initial value */
+#define JOF_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 */
@@ -93,6 +97,7 @@ typedef enum JSOp {
 #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))
@@ -107,7 +112,7 @@ typedef enum JSOp {
 #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))
+                                 (pc)[2] = JUMP_OFFSET_LO(off))
 #define JUMP_OFFSET_MIN         ((int16)0x8000)
 #define JUMP_OFFSET_MAX         ((int16)0x7fff)
 
@@ -124,7 +129,7 @@ typedef enum JSOp {
  */
 #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))
+                                 (pc)[2] = JUMP_OFFSET_LO(i))
 #define SPANDEP_INDEX_MAX       ((uint16)0xfffe)
 #define SPANDEP_INDEX_HUGE      ((uint16)0xffff)
 
@@ -143,16 +148,36 @@ typedef enum JSOp {
 #define JUMPX_OFFSET_MIN        ((int32)0x80000000)
 #define JUMPX_OFFSET_MAX        ((int32)0x7fffffff)
 
-/* A literal is indexed by a per-script atom map. */
+/*
+ * 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(index)    ((jsbytecode)((index) >> 8))
-#define ATOM_INDEX_LO(index)    ((jsbytecode)(index))
+#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,index)((pc)[1] = ATOM_INDEX_HI(index),              \
-                                (pc)[2] = ATOM_INDEX_LO(index))
+#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))
-#define ATOM_INDEX_LIMIT_LOG2   16
+                                           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. */
@@ -192,6 +217,7 @@ 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[];
@@ -230,12 +256,12 @@ js_puts(JSPrinter *jp, const char *s);
  */
 #include <stdio.h>
 
-extern JS_FRIEND_API(void)
+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);
+                JSBool lines, FILE *fp);
 #endif /* DEBUG */
 
 /*
@@ -265,7 +291,7 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun);
  */
 extern JSString *
 js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
-                          JSString *fallback);
+                           JSString *fallback);
 
 #define JSDVG_IGNORE_STACK      0
 #define JSDVG_SEARCH_STACK      1
index c4996f349ecb7f752b8aa22760b83c7c3ccfeb7d..6e649413ef0f7631bb8a4501505a1ed0e4bd57f0 100644 (file)
@@ -62,8 +62,8 @@
  * prec         Operator precedence, zero if not an operator
  * format       Bytecode plus immediate operand encoding format
  *
- * This file is best viewed with 116 columns:
-01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345
+ * This file is best viewed with 128 columns:
+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
  */
 
 /* legend: op         val name          image       len use def prec  format */
@@ -147,8 +147,8 @@ OPDEF(JSOP_OR,        68, "or",         NULL,         3,  1,  0,  0,  JOF_JUMP|J
 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)
-OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL,   -1,  1,  0,  0,  JOF_LOOKUPSWITCH)
+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)
@@ -188,8 +188,8 @@ OPDEF(JSOP_UINT16,    88, "uint16",     NULL,         3,  0,  1, 12,  JOF_UINT16
 /* Object and array literal support. */
 OPDEF(JSOP_NEWINIT,   89, "newinit",    NULL,         1,  2,  1, 10,  JOF_BYTE)
 OPDEF(JSOP_ENDINIT,   90, "endinit",    NULL,         1,  0,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_INITPROP,  91, "initprop",   NULL,         3,  1,  0,  0,  JOF_CONST|JOF_PROP)
-OPDEF(JSOP_INITELEM,  92, "initelem",   NULL,         1,  2,  0,  0,  JOF_BYTE |JOF_ELEM)
+OPDEF(JSOP_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)
 
@@ -225,8 +225,8 @@ OPDEF(JSOP_INSTANCEOF,112,js_instanceof_str,js_instanceof_str,1,2,1,6,JOF_BYTE|J
 OPDEF(JSOP_DEBUGGER,  113,"debugger",   NULL,         1,  0,  0,  0,  JOF_BYTE)
 
 /* gosub/retsub for finally handling */
-OPDEF(JSOP_GOSUB,     114,"gosub",      NULL,         3,  0,  1,  0,  JOF_JUMP)
-OPDEF(JSOP_RETSUB,    115,"retsub",     NULL,         1,  1,  0,  0,  JOF_BYTE)
+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)
@@ -256,15 +256,15 @@ OPDEF(JSOP_ENUMELEM,  122,"enumelem",   NULL,         1,  3,  0,  1,  JOF_BYTE |
  * an assignment or a property initializer code, which then defines a property
  * getter or setter.
  */
-OPDEF(JSOP_GETTER,    123,js_getter_str,js_getter_str,1,  0,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_SETTER,    124,js_setter_str,js_setter_str,1,  0,  0,  0,  JOF_BYTE)
+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_NAME|JOF_DECLARING)
-OPDEF(JSOP_DEFVAR,    127,"defvar",     NULL,         3,  0,  0,  0,  JOF_CONST|JOF_NAME|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)
@@ -272,8 +272,11 @@ OPDEF(JSOP_ANONFUNOBJ,  128, "anonfunobj",  NULL,     3,  0,  1, 12,  JOF_CONST)
 /* ECMA ed. 3 named function expression. */
 OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL,     3,  0,  1, 12,  JOF_CONST)
 
-/* Like JSOP_INITPROP, but specialized to make a DontDelete property for ECMA ed. 3 catch variables. */
-OPDEF(JSOP_INITCATCHVAR,130, "initcatchvar",NULL,     3,  1,  0,  0,  JOF_CONST|JOF_PROP)
+/*
+ * 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)
@@ -309,7 +312,7 @@ OPDEF(JSOP_ARGCNT,      137,"argcnt",     NULL,       1,  0,  1, 12,  JOF_BYTE)
  * The local variable's slot number is the first immediate two-byte operand.
  * The function object's atom index is the second immediate operand.
  */
-OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL,       5,  0,  0,  0,  JOF_DEFLOCALVAR|JOF_DECLARING)
+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)
@@ -317,16 +320,18 @@ OPDEF(JSOP_IFEQX,         140,"ifeqx",    NULL,       5,  1,  0,  0,  JOF_JUMPX|
 OPDEF(JSOP_IFNEX,         141,"ifnex",    NULL,       5,  1,  0,  0,  JOF_JUMPX)
 OPDEF(JSOP_ORX,           142,"orx",      NULL,       5,  1,  0,  0,  JOF_JUMPX|JOF_DETECTING)
 OPDEF(JSOP_ANDX,          143,"andx",     NULL,       5,  1,  0,  0,  JOF_JUMPX|JOF_DETECTING)
-OPDEF(JSOP_GOSUBX,        144,"gosubx",   NULL,       5,  0,  1,  0,  JOF_JUMPX)
+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)
-OPDEF(JSOP_LOOKUPSWITCHX, 148,"lookupswitchx",NULL,  -1,  1,  0,  0,  JOF_LOOKUPSWITCHX)
+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)
-OPDEF(JSOP_BACKPATCH_PUSH,151,"backpatch_push",NULL,  3,  0,  1,  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)
@@ -340,5 +345,52 @@ OPDEF(JSOP_DECGVAR,       157,"decgvar",  NULL,       3,  0,  1, 10,  JOF_CONST|
 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. */
+/* 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)
index c93eee2f1551649a3fc94319744aad1af3827da2..e9c4a5534b316ca656447de5cf9ae9508a825999 100644 (file)
 #endif
 #endif /* XP_WIN || XP_OS2 */
 
-#ifdef XP_MAC
-#define JS_HAVE_LONG_LONG
-
-JS_BEGIN_EXTERN_C
-
-#include <stddef.h>
-
-extern void* reallocSmaller(void* block, size_t newSize);
-
-extern char* strdup(const char* str);
-
-JS_END_EXTERN_C
-
-#endif /* XP_MAC */
-
 #ifdef XP_BEOS
 #define JS_HAVE_LONG_LONG
 #endif
index ad8b5203e3059808717d165e6f23347b6fb19a1c..ede1221b8121c2cc18af221b4a772b7742623b37 100644 (file)
@@ -75,7 +75,7 @@ typedef JSUintn uint;
 
 typedef JSUintn uintn;
 typedef JSUint64 uint64;
-#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2)
+#if !defined(_WIN32) && !defined(XP_OS2)
 typedef JSUint32 uint32;
 #else
 typedef unsigned long uint32;
@@ -102,7 +102,7 @@ typedef JSInt64 int64;
 #ifdef HPUX
 #include <model.h>
 #else
-#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2)
+#if !defined(_WIN32) && !defined(XP_OS2)
 typedef JSInt32 int32;
 #else
 typedef long int32;
@@ -112,14 +112,14 @@ typedef JSInt8 int8;
 #endif /* HPUX */
 #endif /* AIX && HAVE_SYS_INTTYPES_H */
 
-#endif /* XP_BEOS */
+#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
+#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
@@ -199,13 +199,4 @@ typedef JSFloat64 float64;
 #define PR_CompareStrings PL_CompareStrings
 #define PR_CompareValues PL_CompareValues
 
-#ifdef XP_MAC
-#ifndef TRUE                           /* Mac standard is lower case true */
-       #define TRUE 1
-#endif
-#ifndef FALSE                          /* Mac standard is lower case false */
-       #define FALSE 0
-#endif
-#endif
-
 #endif /* !defined(PROTYPES_H) */
index 6b3f7600c5e009a7e4b4b4ccc338ebb99a6ac69a..1438f35a21b2acb8c233d4a6ab9be53b7200f0a2 100644 (file)
@@ -48,9 +48,7 @@
  * compile-time expressions.  Finally, it calls js_EmitTree (see jsemit.h) to
  * generate bytecode.
  *
- * This parser attempts no error recovery.  The dense JSTokenType enumeration
- * was designed with error recovery built on 64-bit first and follow bitsets
- * in mind, however.
+ * This parser attempts no error recovery.
  */
 #include "jsstddef.h"
 #include <stdlib.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 and a token stream, and emits bytecode using
- * a code generator.
+ * 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 *
@@ -121,7 +123,8 @@ static JSParser PrimaryExpr;
 #define MUST_MATCH_TOKEN(tt, errno)                                           \
     JS_BEGIN_MACRO                                                            \
         if (js_GetToken(cx, ts) != tt) {                                      \
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, errno); \
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, \
+                            errno);                                           \
             return NULL;                                                      \
         }                                                                     \
     JS_END_MACRO
@@ -130,7 +133,7 @@ static JSParser PrimaryExpr;
     JS_BEGIN_MACRO                                                            \
         int stackDummy;                                                       \
         if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {                           \
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,         \
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, \
                                         JSMSG_OVER_RECURSED);                 \
             return NULL;                                                      \
         }                                                                     \
@@ -142,17 +145,21 @@ static uint32 maxparsenodes = 0;
 static uint32 recyclednodes = 0;
 #endif
 
-static void
+static JSParseNode *
 RecycleTree(JSParseNode *pn, JSTreeContext *tc)
 {
+    JSParseNode *next;
+
     if (!pn)
-        return;
+        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 *
@@ -202,6 +209,13 @@ NewOrRecycledNode(JSContext *cx, JSTreeContext *tc)
             break;
         }
     }
+#ifdef METER_PARSENODES
+    if (pn) {
+        parsenodes++;
+        if (parsenodes - recyclednodes > maxparsenodes)
+            maxparsenodes = parsenodes - recyclednodes;
+    }
+#endif
     return pn;
 }
 
@@ -209,23 +223,23 @@ NewOrRecycledNode(JSContext *cx, JSTreeContext *tc)
  * Allocate a JSParseNode from cx's temporary arena.
  */
 static JSParseNode *
-NewParseNode(JSContext *cx, JSToken *tok, JSParseNodeArity arity,
+NewParseNode(JSContext *cx, JSTokenStream *ts, JSParseNodeArity arity,
              JSTreeContext *tc)
 {
     JSParseNode *pn;
+    JSToken *tp;
 
     pn = NewOrRecycledNode(cx, tc);
     if (!pn)
         return NULL;
-    pn->pn_type = tok->type;
-    pn->pn_pos = tok->pos;
+    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;
-#ifdef METER_PARSENODES
-    parsenodes++;
-    if (parsenodes - recyclednodes > maxparsenodes)
-        maxparsenodes = parsenodes - recyclednodes;
+#if JS_HAS_XML_SUPPORT
+    pn->pn_ts = ts;
 #endif
     return pn;
 }
@@ -252,7 +266,6 @@ NewBinary(JSContext *cx, JSTokenType tt,
             left->pn_arity = PN_LIST;
             PN_INIT_LIST_1(left, pn1);
             PN_APPEND(left, pn2);
-            left->pn_extra = 0;
             if (tt == TOK_PLUS) {
                 if (pn1->pn_type == TOK_STRING)
                     left->pn_extra |= PNX_STRCAT;
@@ -302,10 +315,8 @@ NewBinary(JSContext *cx, JSTokenType tt,
     pn->pn_left = left;
     pn->pn_right = right;
     pn->pn_next = NULL;
-#ifdef METER_PARSENODES
-    parsenodes++;
-    if (parsenodes - recyclednodes > maxparsenodes)
-        maxparsenodes = parsenodes - recyclednodes;
+#if JS_HAS_XML_SUPPORT
+    pn->pn_ts = NULL;
 #endif
     return pn;
 }
@@ -332,7 +343,7 @@ CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
         return TOK_NAME;
     (void) js_GetToken(cx, ts);
     if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
-        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_BAD_GETTER_OR_SETTER,
                                     (op == JSOP_GETTER)
                                     ? js_getter_str
@@ -342,7 +353,8 @@ CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
     CURRENT_TOKEN(ts).t_op = op;
     name = js_AtomToPrintableString(cx, atom);
     if (!name ||
-        !js_ReportCompileErrorNumber(cx, ts, NULL,
+        !js_ReportCompileErrorNumber(cx, ts,
+                                     JSREPORT_TS |
                                      JSREPORT_WARNING |
                                      JSREPORT_STRICT,
                                      JSMSG_DEPRECATED_USAGE,
@@ -377,13 +389,17 @@ js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts)
                 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_AllocGCThing), or
+     *   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.
@@ -393,7 +409,7 @@ js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts)
     pn = Statements(cx, ts, &tc);
     if (pn) {
         if (!js_MatchToken(cx, ts, TOK_EOF)) {
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_SYNTAX_ERROR);
             pn = NULL;
         } else {
@@ -438,6 +454,10 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
                 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;
@@ -453,7 +473,7 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
     if (!pn) {
         ok = JS_FALSE;
     } else if (!js_MatchToken(cx, ts, TOK_EOF)) {
-        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_SYNTAX_ERROR);
         ok = JS_FALSE;
     } else {
@@ -548,6 +568,9 @@ HasFinalReturn(JSParseNode *pn)
       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;
@@ -588,12 +611,14 @@ ReportNoReturnValue(JSContext *cx, JSTokenStream *ts)
     fun = cx->fp->fun;
     if (fun->atom) {
         char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));
-        ok = js_ReportCompileErrorNumber(cx, ts, NULL,
+        ok = js_ReportCompileErrorNumber(cx, ts,
+                                         JSREPORT_TS |
                                          JSREPORT_WARNING |
                                          JSREPORT_STRICT,
                                          JSMSG_NO_RETURN_VALUE, name);
     } else {
-        ok = js_ReportCompileErrorNumber(cx, ts, NULL,
+        ok = js_ReportCompileErrorNumber(cx, ts,
+                                         JSREPORT_TS |
                                          JSREPORT_WARNING |
                                          JSREPORT_STRICT,
                                          JSMSG_ANON_NO_RETURN_VALUE);
@@ -624,7 +649,8 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
         frame.fun = fun;
         frame.varobj = frame.scopeChain = funobj;
         frame.down = fp;
-        frame.flags = (fp->flags & JSFRAME_COMPILE_N_GO);
+        if (fp)
+            frame.flags = fp->flags & JSFRAME_COMPILE_N_GO;
         cx->fp = &frame;
     }
 
@@ -640,7 +666,7 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
     }
 
     cx->fp = fp;
-    tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
+    tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS));
     return pn;
 }
 
@@ -718,8 +744,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
             JSBool lambda)
 {
     JSOp op, prevop;
-    JSParseNode *pn, *body;
-    JSAtom *funAtom, *argAtom;
+    JSParseNode *pn, *body, *result;
+    JSAtom *funAtom, *objAtom, *argAtom;
     JSStackFrame *fp;
     JSObject *varobj, *pobj;
     JSAtomListElement *ale;
@@ -733,12 +759,19 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
 #if JS_HAS_GETTER_SETTER
     op = CURRENT_TOKEN(ts).t_op;
 #endif
-    pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC, tc);
+    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;
@@ -755,11 +788,12 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
             if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) {
                 const char *name = js_AtomToPrintableString(cx, funAtom);
                 if (!name ||
-                    !js_ReportCompileErrorNumber(cx, ts, NULL,
+                    !js_ReportCompileErrorNumber(cx, ts,
                                                  (prevop != JSOP_DEFCONST)
-                                                 ? JSREPORT_WARNING |
+                                                 ? JSREPORT_TS |
+                                                   JSREPORT_WARNING |
                                                    JSREPORT_STRICT
-                                                 : JSREPORT_ERROR,
+                                                 : JSREPORT_TS | JSREPORT_ERROR,
                                                  JSMSG_REDECLARED_VAR,
                                                  (prevop == JSOP_DEFFUN ||
                                                   prevop == JSOP_CLOSURE)
@@ -786,32 +820,49 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
          * local variable to bind its name to its value, and not an activation
          * object property (it might also need the activation property, if the
          * outer function contains with statements, e.g., but the stack slot
-         * wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a
+         * 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 LookupArgOrVar
+             * Define a property on the outer function so that BindNameToSlot
              * can properly optimize accesses.
-             *
-             * XXX Here and in Variables, we use the function object's scope,
-             * XXX arguably polluting it, when we could use a compiler-private
-             * XXX scope structure.  Tradition!
              */
             JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
             JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj));
-            if (!js_LookupProperty(cx, varobj, (jsid)funAtom, &pobj, &prop))
+            if (!js_LookupHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom),
+                                         &pobj, &prop)) {
                 return NULL;
+            }
             if (prop)
                 OBJ_DROP_PROPERTY(cx, pobj, prop);
-            if (!prop || pobj != varobj) {
-                if (!js_DefineNativeProperty(cx, varobj, (jsid)funAtom,
-                                             JSVAL_VOID,
-                                             js_GetLocalVariable,
-                                             js_SetLocalVariable,
-                                             JSPROP_ENUMERATE | JSPROP_SHARED,
-                                             SPROP_HAS_SHORTID, fp->fun->nvars,
-                                             NULL)) {
+            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++;
@@ -829,6 +880,27 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
         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)) {
@@ -836,8 +908,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
             MUST_MATCH_TOKEN(TOK_NAME, JSMSG_MISSING_FORMAL);
             argAtom = CURRENT_TOKEN(ts).t_atom;
             pobj = NULL;
-            if (!js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
-                                   &prop)) {
+            if (!js_LookupHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
+                                         &pobj, &prop)) {
                 return NULL;
             }
             dupflag = 0;
@@ -854,7 +926,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
                      * mapped by an entry in scope.
                      */
                     ok = name &&
-                         js_ReportCompileErrorNumber(cx, ts, NULL,
+                         js_ReportCompileErrorNumber(cx, ts,
+                                                     JSREPORT_TS |
                                                      JSREPORT_WARNING |
                                                      JSREPORT_STRICT,
                                                      JSMSG_DUPLICATE_FORMAL,
@@ -867,15 +940,19 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
                     return NULL;
                 prop = NULL;
             }
-            if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
+            if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
                                       js_GetArgument, js_SetArgument,
                                       SPROP_INVALID_SLOT,
-                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
-                                      JSPROP_SHARED,
-                                      SPROP_HAS_SHORTID | dupflag,
+                                      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));
 
@@ -918,14 +995,27 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
     }
 #endif
 
+    result = pn;
 #if JS_HAS_LEXICAL_CLOSURE
-    if (lambda || !funAtom) {
+    if (lambda) {
+        /*
+         * ECMA ed. 3 standard: function expression, possibly anonymous.
+         */
+        op = funAtom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;
+    } else if (!funAtom) {
         /*
-         * ECMA ed. 3 standard: function expression, possibly anonymous (even
-         * if at top-level, an unnamed function is an expression statement, not
-         * a function declaration).
+         * 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.
          */
-        op = fun->atom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;
+        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
@@ -938,23 +1028,13 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
 #endif
         op = JSOP_NOP;
 
-    /*
-     * 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.
-     */
-    pn->pn_funAtom = js_AtomizeObject(cx, fun->object, 0);
-    if (!pn->pn_funAtom)
-        return NULL;
-
+    pn->pn_funAtom = objAtom;
     pn->pn_op = op;
     pn->pn_body = body;
-    pn->pn_flags = funtc.flags & TCF_FUN_FLAGS;
+    pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS);
     pn->pn_tryCount = funtc.tryCount;
     TREE_CONTEXT_FINISH(&funtc);
-    return pn;
+    return result;
 }
 
 static JSParseNode *
@@ -984,7 +1064,7 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
     CHECK_RECURSION();
 
-    pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+    pn = NewParseNode(cx, ts, PN_LIST, tc);
     if (!pn)
         return NULL;
     PN_INIT_LIST(pn);
@@ -993,8 +1073,11 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
     while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {
         ts->flags &= ~TSF_OPERAND;
         pn2 = Statement(cx, ts, tc);
-        if (!pn2)
+        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. */
@@ -1058,9 +1141,11 @@ Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         pn->pn_op == JSOP_NOP &&
         pn->pn_right->pn_type > TOK_EQOP)
     {
-        JSBool rewrite = !JSVERSION_IS_ECMA(cx->version);
-        if (!js_ReportCompileErrorNumber(cx, ts, NULL,
-                                         JSREPORT_WARNING | JSREPORT_STRICT,
+        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"
@@ -1116,11 +1201,11 @@ MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
 static JSParseNode *
 ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 {
-    JSParseNode *pn, *pn2, *pn3;
+    JSParseNode *pn, *pn2;
     JSTokenType tt;
 
     MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);
-    pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+    pn = NewParseNode(cx, ts, PN_NAME, tc);
     if (!pn)
         return NULL;
     pn->pn_op = JSOP_NAME;
@@ -1136,7 +1221,7 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             goto bad_import;
 
         if (tt == TOK_DOT) {
-            pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+            pn2 = NewParseNode(cx, ts, PN_NAME, tc);
             if (!pn2)
                 return NULL;
             if (js_MatchToken(cx, ts, TOK_STAR)) {
@@ -1153,21 +1238,12 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             pn2->pn_pos.begin = pn->pn_pos.begin;
             pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
         } else {
-            /* Make a TOK_LB node. */
-            pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+            /* Make a TOK_LB binary node. */
+            pn2 = NewBinary(cx, tt, JSOP_GETELEM, pn, Expr(cx, ts, tc), tc);
             if (!pn2)
                 return NULL;
-            pn3 = Expr(cx, ts, tc);
-            if (!pn3)
-                return NULL;
 
             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
-            pn2->pn_pos.begin = pn->pn_pos.begin;
-            pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
-
-            pn2->pn_op = JSOP_GETELEM;
-            pn2->pn_left = pn;
-            pn2->pn_right = pn3;
         }
 
         pn = pn2;
@@ -1193,7 +1269,8 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
     return pn;
 
   bad_import:
-    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_IMPORT);
+    js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
+                                JSMSG_BAD_IMPORT);
     return NULL;
 }
 #endif /* JS_HAS_EXPORT_IMPORT */
@@ -1225,19 +1302,19 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
     switch (tt) {
 #if JS_HAS_EXPORT_IMPORT
       case TOK_EXPORT:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+        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, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+            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, &CURRENT_TOKEN(ts), PN_NAME, tc);
+                pn2 = NewParseNode(cx, ts, PN_NAME, tc);
                 if (!pn2)
                     return NULL;
                 pn2->pn_op = JSOP_NAME;
@@ -1253,7 +1330,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         break;
 
       case TOK_IMPORT:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+        pn = NewParseNode(cx, ts, PN_LIST, tc);
         if (!pn)
             return NULL;
         PN_INIT_LIST(pn);
@@ -1269,11 +1346,15 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 #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, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+        pn = NewParseNode(cx, ts, PN_TERNARY, tc);
         if (!pn)
             return NULL;
         pn1 = Condition(cx, ts, tc);
@@ -1305,7 +1386,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         JSParseNode *pn5;
         JSBool seenDefault = JS_FALSE;
 
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+        pn = NewParseNode(cx, ts, PN_BINARY, tc);
         if (!pn)
             return NULL;
         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
@@ -1319,7 +1400,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
 
         /* pn2 is a list of case nodes. The default case has pn_left == NULL */
-        pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+        pn2 = NewParseNode(cx, ts, PN_LIST, tc);
         if (!pn2)
             return NULL;
         PN_INIT_LIST(pn2);
@@ -1330,7 +1411,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             switch (tt) {
               case TOK_DEFAULT:
                 if (seenDefault) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_TOO_MANY_DEFAULTS);
                     return NULL;
                 }
@@ -1338,7 +1420,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 /* fall through */
 
               case TOK_CASE:
-                pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+                pn3 = NewParseNode(cx, ts, PN_BINARY, tc);
                 if (!pn3)
                     return NULL;
                 if (tt == TOK_DEFAULT) {
@@ -1350,7 +1432,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 }
                 PN_APPEND(pn2, pn3);
                 if (pn2->pn_count == JS_BIT(16)) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_TOO_MANY_CASES);
                     return NULL;
                 }
@@ -1360,19 +1443,22 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 return NULL;
 
               default:
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                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, &CURRENT_TOKEN(ts), PN_LIST, tc);
+            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);
@@ -1380,7 +1466,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                     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)
@@ -1399,7 +1487,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 #endif /* JS_HAS_SWITCH_STATEMENT */
 
       case TOK_WHILE:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+        pn = NewParseNode(cx, ts, PN_BINARY, tc);
         if (!pn)
             return NULL;
         js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);
@@ -1417,7 +1505,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
 #if JS_HAS_DO_WHILE_LOOP
       case TOK_DO:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+        pn = NewParseNode(cx, ts, PN_BINARY, tc);
         if (!pn)
             return NULL;
         js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
@@ -1432,7 +1520,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         js_PopStatement(tc);
         pn->pn_pos.end = pn2->pn_pos.end;
         pn->pn_right = pn2;
-        if (cx->version != JSVERSION_ECMA_3) {
+        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
@@ -1446,16 +1534,31 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
       case TOK_FOR:
         /* A FOR node is binary, left is loop control and right is the body. */
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+        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 {
@@ -1495,12 +1598,22 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             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, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_BAD_FOR_LEFTSIDE);
                 return NULL;
             }
@@ -1515,6 +1628,14 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                     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'. */
@@ -1529,6 +1650,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 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;
@@ -1556,7 +1682,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             }
 
             /* Build the RESERVED node to use as the left kid of pn. */
-            pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+            pn4 = NewParseNode(cx, ts, PN_TERNARY, tc);
             if (!pn4)
                 return NULL;
             pn4->pn_type = TOK_RESERVED;
@@ -1580,6 +1706,14 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         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;
@@ -1601,7 +1735,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
          *
          * finally nodes are unary (just the finally expression)
          */
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+        pn = NewParseNode(cx, ts, PN_TERNARY, tc);
         pn->pn_op = JSOP_NOP;
 
         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
@@ -1616,7 +1750,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         while (js_PeekToken(cx, ts) == TOK_CATCH) {
             /* check for another catch after unconditional catch */
             if (catchtail != pn && !catchtail->pn_kid1->pn_expr) {
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_CATCH_AFTER_GENERAL);
                 return NULL;
             }
@@ -1628,7 +1763,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
              * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
              */
             (void) js_GetToken(cx, ts); /* eat `catch' */
-            pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+            pn2 = NewParseNode(cx, ts, PN_TERNARY, tc);
             if (!pn2)
                 return NULL;
 
@@ -1638,7 +1773,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
              */
             MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
             MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER);
-            pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+            pn3 = NewParseNode(cx, ts, PN_NAME, tc);
             if (!pn3)
                 return NULL;
 
@@ -1686,7 +1821,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             pn->pn_kid3 = NULL;
         }
         if (!pn->pn_kid2 && !pn->pn_kid3) {
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_CATCH_OR_FINALLY);
             return NULL;
         }
@@ -1695,7 +1830,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
       }
 
       case TOK_THROW:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
 
@@ -1706,7 +1841,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         if (tt == TOK_ERROR)
             return NULL;
         if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) {
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_SYNTAX_ERROR);
             return NULL;
         }
@@ -1721,19 +1856,19 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
       /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
       case TOK_CATCH:
-        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_CATCH_WITHOUT_TRY);
         return NULL;
 
       case TOK_FINALLY:
-        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_FINALLY_WITHOUT_TRY);
         return NULL;
 
 #endif /* JS_HAS_EXCEPTIONS */
 
       case TOK_BREAK:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+        pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
         if (!MatchLabel(cx, ts, pn))
@@ -1743,7 +1878,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         if (label) {
             for (; ; stmt = stmt->down) {
                 if (!stmt) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_LABEL_NOT_FOUND);
                     return NULL;
                 }
@@ -1753,7 +1889,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         } else {
             for (; ; stmt = stmt->down) {
                 if (!stmt) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_TOUGH_BREAK);
                     return NULL;
                 }
@@ -1766,7 +1903,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         break;
 
       case TOK_CONTINUE:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+        pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
         if (!MatchLabel(cx, ts, pn))
@@ -1776,14 +1913,16 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         if (label) {
             for (stmt2 = NULL; ; stmt = stmt->down) {
                 if (!stmt) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    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, NULL,
+                            js_ReportCompileErrorNumber(cx, ts,
+                                                        JSREPORT_TS |
                                                         JSREPORT_ERROR,
                                                         JSMSG_BAD_CONTINUE);
                             return NULL;
@@ -1797,7 +1936,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         } else {
             for (; ; stmt = stmt->down) {
                 if (!stmt) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_BAD_CONTINUE);
                     return NULL;
                 }
@@ -1810,14 +1950,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         break;
 
       case TOK_WITH:
-        if (!js_ReportCompileErrorNumber(cx, ts, NULL,
-                                         JSREPORT_WARNING | JSREPORT_STRICT,
-                                         JSMSG_DEPRECATED_USAGE,
-                                         js_with_statement_str)) {
-            return NULL;
-        }
-
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+        pn = NewParseNode(cx, ts, PN_BINARY, tc);
         if (!pn)
             return NULL;
         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
@@ -1849,11 +1982,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
       case TOK_RETURN:
         if (!(tc->flags & TCF_IN_FUNCTION)) {
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_BAD_RETURN);
             return NULL;
         }
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
 
@@ -1899,7 +2032,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
       case TOK_EOL:
       case TOK_SEMI:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
         pn->pn_type = TOK_SEMI;
@@ -1908,7 +2041,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
 #if JS_HAS_DEBUGGER_KEYWORD
       case TOK_DEBUGGER:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+        pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
         pn->pn_type = TOK_DEBUGGER;
@@ -1916,10 +2049,38 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         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)
@@ -1927,14 +2088,16 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
         if (js_PeekToken(cx, ts) == TOK_COLON) {
             if (pn2->pn_type != TOK_NAME) {
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                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, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_DUPLICATE_LABEL);
                     return NULL;
                 }
@@ -1956,7 +2119,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             return pn2;
         }
 
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
         pn->pn_type = TOK_SEMI;
@@ -1971,7 +2134,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         if (tt == TOK_ERROR)
             return NULL;
         if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_SEMI_BEFORE_STMNT);
             return NULL;
         }
@@ -2006,11 +2169,10 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
      * this by looking up the variable id in the current variable scope.
      */
     JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_VAR);
-    pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+    pn = NewParseNode(cx, ts, PN_LIST, tc);
     if (!pn)
         return NULL;
     pn->pn_op = CURRENT_TOKEN(ts).t_op;
-    pn->pn_extra = 0;                   /* assume no JSOP_POP needed */
     PN_INIT_LIST(pn);
 
     /*
@@ -2053,17 +2215,18 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         ATOM_LIST_SEARCH(ale, &tc->decls, atom);
         if (ale) {
             prevop = ALE_JSOP(ale);
-            if (JS_HAS_STRICT_OPTION(cx) ||
-                pn->pn_op == JSOP_DEFCONST ||
-                prevop == JSOP_DEFCONST) {
+            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, NULL,
+                    !js_ReportCompileErrorNumber(cx, ts,
                                                  (pn->pn_op != JSOP_DEFCONST &&
                                                   prevop != JSOP_DEFCONST)
-                                                 ? JSREPORT_WARNING |
+                                                 ? JSREPORT_TS |
+                                                   JSREPORT_WARNING |
                                                    JSREPORT_STRICT
-                                                 : JSREPORT_ERROR,
+                                                 : JSREPORT_TS | JSREPORT_ERROR,
                                                  JSMSG_REDECLARED_VAR,
                                                  (prevop == JSOP_DEFFUN ||
                                                   prevop == JSOP_CLOSURE)
@@ -2084,7 +2247,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         }
         ALE_SET_JSOP(ale, pn->pn_op);
 
-        pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc);
+        pn2 = NewParseNode(cx, ts, PN_NAME, tc);
         if (!pn2)
             return NULL;
         pn2->pn_op = JSOP_NAME;
@@ -2092,15 +2255,20 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         pn2->pn_expr = NULL;
         pn2->pn_slot = -1;
         pn2->pn_attrs = (pn->pn_op == JSOP_DEFCONST)
-                        ? JSPROP_ENUMERATE | JSPROP_PERMANENT |
-                          JSPROP_READONLY
-                        : JSPROP_ENUMERATE | JSPROP_PERMANENT;
+                        ? JSPROP_PERMANENT | JSPROP_READONLY
+                        : JSPROP_PERMANENT;
         PN_APPEND(pn, pn2);
 
         if (!fun) {
-            prop = NULL; /* don't lookup global variables at compile time */
+            /* 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, (jsid)atom, &pobj, &prop))
+            if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
                 return NULL;
         }
         if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) {
@@ -2110,14 +2278,16 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 if (!name) {
                     ok = JS_FALSE;
                 } else if (pn->pn_op == JSOP_DEFCONST) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    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, NULL,
+                    ok = js_ReportCompileErrorNumber(cx, ts,
+                                                     JSREPORT_TS |
                                                      JSREPORT_WARNING |
                                                      JSREPORT_STRICT,
                                                      JSMSG_VAR_HIDES_ARG,
@@ -2129,7 +2299,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                     if (clasp == &js_FunctionClass) {
                         JS_ASSERT(sprop->getter == js_GetLocalVariable);
                         JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
-                                  sprop->shortid < fun->nvars);
+                                  (uint16) sprop->shortid < fun->nvars);
                     } else if (clasp == &js_CallClass) {
                         if (sprop->getter == js_GetCallVariable) {
                             /*
@@ -2138,7 +2308,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                              * that the slot number we have is in range.
                              */
                             JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
-                                      sprop->shortid < fun->nvars);
+                                      (uint16) sprop->shortid < fun->nvars);
                         } else {
                             /*
                              * A variable introduced through another eval:
@@ -2182,12 +2352,17 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 atom != cx->runtime->atomState.argumentsAtom &&
                 fp->scopeChain == obj &&
                 !js_InWithStatement(tc)) {
-                if (!js_AddNativeProperty(cx, obj, (jsid)atom,
+                if (!js_AddHiddenProperty(cx, obj, ATOM_TO_JSID(atom),
                                           currentGetter, currentSetter,
                                           SPROP_INVALID_SLOT,
                                           pn2->pn_attrs | JSPROP_SHARED,
                                           SPROP_HAS_SHORTID, fun->nvars)) {
-                    ok = JS_FALSE;
+                    return NULL;
+                }
+                if (fun->nvars == JS_BITMASK(16)) {
+                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                         JSMSG_TOO_MANY_FUN_VARS);
+                    return NULL;
                 }
                 fun->nvars++;
             }
@@ -2195,7 +2370,8 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
         if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
             if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_BAD_VAR_INIT);
                 ok = JS_FALSE;
             } else {
@@ -2229,7 +2405,7 @@ Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
     pn = AssignExpr(cx, ts, tc);
     if (pn && js_MatchToken(cx, ts, TOK_COMMA)) {
-        pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+        pn2 = NewParseNode(cx, ts, PN_LIST, tc);
         if (!pn2)
             return NULL;
         pn2->pn_pos.begin = pn->pn_pos.begin;
@@ -2282,7 +2458,9 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             tc->flags |= TCF_FUN_HEAVYWEIGHT;
         break;
       case TOK_DOT:
-        pn2->pn_op = JSOP_SETPROP;
+        pn2->pn_op = (pn2->pn_op == JSOP_GETMETHOD)
+                     ? JSOP_SETMETHOD
+                     : JSOP_SETPROP;
         break;
       case TOK_LB:
         pn2->pn_op = JSOP_SETELEM;
@@ -2291,9 +2469,17 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
       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, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_BAD_LEFTSIDE_OF_ASS);
         return NULL;
     }
@@ -2312,7 +2498,7 @@ CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
     pn = OrExpr(cx, ts, tc);
     if (pn && js_MatchToken(cx, ts, TOK_HOOK)) {
         pn1 = pn;
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc);
+        pn = NewParseNode(cx, ts, PN_TERNARY, tc);
         if (!pn)
             return NULL;
 #if JS_HAS_IN_OPERATOR
@@ -2519,9 +2705,12 @@ SetLvalKid(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, JSParseNode *kid,
         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, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_BAD_OPERAND, name);
         return NULL;
     }
@@ -2558,7 +2747,15 @@ SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
 
 #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)
@@ -2580,6 +2777,8 @@ 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;
@@ -2588,7 +2787,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
       case TOK_UNARYOP:
       case TOK_PLUS:
       case TOK_MINUS:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
         pn->pn_type = TOK_UNARYOP;      /* PLUS and MINUS are binary */
@@ -2602,7 +2801,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
       case TOK_INC:
       case TOK_DEC:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
         pn2 = MemberExpr(cx, ts, tc, JS_TRUE);
@@ -2614,7 +2813,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         break;
 
       case TOK_DELETE:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
         pn2 = UnaryExpr(cx, ts, tc);
@@ -2645,7 +2844,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
             tt = js_PeekTokenSameLine(cx, ts);
             if (tt == TOK_INC || tt == TOK_DEC) {
                 (void) js_GetToken(cx, ts);
-                pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+                pn2 = NewParseNode(cx, ts, PN_UNARY, tc);
                 if (!pn2)
                     return NULL;
                 if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE))
@@ -2677,7 +2876,7 @@ ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
         } while (js_MatchToken(cx, ts, TOK_COMMA));
 
         if (js_GetToken(cx, ts) != TOK_RP) {
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_PAREN_AFTER_ARGS);
             return JS_FALSE;
         }
@@ -2701,7 +2900,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
     if (tt == TOK_NEW) {
         (void) js_GetToken(cx, ts);
 
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+        pn = NewParseNode(cx, ts, PN_LIST, tc);
         if (!pn)
             return NULL;
         pn2 = MemberExpr(cx, ts, tc, JS_FALSE);
@@ -2723,21 +2922,102 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
         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, &CURRENT_TOKEN(ts), PN_NAME, tc);
+            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_pos.begin = pn->pn_pos.begin;
-            pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
             pn2->pn_op = JSOP_GETPROP;
             pn2->pn_expr = pn;
             pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
+#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, &CURRENT_TOKEN(ts), PN_BINARY, tc);
+            pn2 = NewParseNode(cx, ts, PN_BINARY, tc);
             if (!pn2)
                 return NULL;
             pn3 = Expr(cx, ts, tc);
@@ -2761,7 +3041,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
                 pn2->pn_right = pn3;
             }
         } else if (allowCallSyntax && tt == TOK_LP) {
-            pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+            pn2 = NewParseNode(cx, ts, PN_LIST, tc);
             if (!pn2)
                 return NULL;
 
@@ -2797,70 +3077,774 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
 }
 
 static JSParseNode *
-PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+BracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 {
-    JSTokenType tt;
-    JSParseNode *pn, *pn2, *pn3;
-    char *badWord;
-#if JS_HAS_GETTER_SETTER
-    JSAtom *atom;
-    JSRuntime *rt;
-#endif
-
-#if JS_HAS_SHARP_VARS
-    JSParseNode *defsharp;
-    JSBool notsharp;
+    uintN oldflags;
+    JSParseNode *pn;
 
-    defsharp = NULL;
-    notsharp = JS_FALSE;
-  again:
+#if JS_HAS_IN_OPERATOR
     /*
-     * 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.
+     * 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;
+}
 
-    CHECK_RECURSION();
+#if JS_HAS_XML_SUPPORT
 
-    ts->flags |= TSF_OPERAND;
-    tt = js_GetToken(cx, ts);
-    ts->flags &= ~TSF_OPERAND;
+static JSParseNode *
+EndBracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
+{
+    JSParseNode *pn;
 
-#if JS_HAS_GETTER_SETTER
-    if (tt == TOK_NAME) {
-        tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);
-        if (tt == TOK_ERROR)
-            return NULL;
-    }
-#endif
+    pn = BracketedExpr(cx, ts, tc);
+    if (!pn)
+        return NULL;
 
-    switch (tt) {
-#if JS_HAS_LEXICAL_CLOSURE
-      case TOK_FUNCTION:
-        pn = FunctionExpr(cx, ts, tc);
-        if (!pn)
-            return NULL;
-        break;
-#endif
+    MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ATTR_EXPR);
+    return pn;
+}
 
-#if JS_HAS_INITIALIZERS
-      case TOK_LB:
-      {
-        JSBool matched;
-        jsuint atomIndex;
+/*
+ * 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, &CURRENT_TOKEN(ts), PN_LIST, tc);
-        if (!pn)
-            return NULL;
-        pn->pn_type = TOK_RB;
-        pn->pn_extra = 0;
+    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;
+}
 
-#if JS_HAS_SHARP_VARS
-        if (defsharp) {
-            PN_INIT_LIST_1(pn, defsharp);
-            defsharp = NULL;
-        } else
+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 (</) sequence
+ * that opens the end tag for the container.
+ */
+static JSBool
+XMLElementContent(JSContext *cx, JSTokenStream *ts, JSParseNode *pn,
+                  JSTreeContext *tc)
+{
+    JSTokenType tt;
+    JSParseNode *pn2;
+    JSAtom *textAtom;
+
+    ts->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 <! followed by -- starting an HTML comment
+     * to end of line (used in script tags to hide content from old browsers
+     * that don't recognize <script>).
+     */
+    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);
 
@@ -2868,7 +3852,14 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         matched = js_MatchToken(cx, ts, TOK_RB);
         ts->flags &= ~TSF_OPERAND;
         if (!matched) {
-            for (atomIndex = 0; atomIndex < ATOM_INDEX_LIMIT; atomIndex++) {
+            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;
@@ -2880,7 +3871,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 if (tt == TOK_COMMA) {
                     /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */
                     js_MatchToken(cx, ts, TOK_COMMA);
-                    pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+                    pn2 = NewParseNode(cx, ts, PN_NULLARY, tc);
                 } else {
                     pn2 = AssignExpr(cx, ts, tc);
                 }
@@ -2902,7 +3893,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
       }
 
       case TOK_LC:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc);
+        pn = NewParseNode(cx, ts, PN_LIST, tc);
         if (!pn)
             return NULL;
         pn->pn_type = TOK_RC;
@@ -2922,7 +3913,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 tt = js_GetToken(cx, ts);
                 switch (tt) {
                   case TOK_NUMBER:
-                    pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+                    pn3 = NewParseNode(cx, ts, PN_NULLARY, tc);
                     if (pn3)
                         pn3->pn_dval = CURRENT_TOKEN(ts).t_dval;
                     break;
@@ -2936,8 +3927,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                              ? JSOP_GETTER
                              : JSOP_SETTER;
                         if (js_MatchToken(cx, ts, TOK_NAME)) {
-                            pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME,
-                                               tc);
+                            pn3 = NewParseNode(cx, ts, PN_NAME, tc);
                             if (!pn3)
                                 return NULL;
                             pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
@@ -2954,12 +3944,13 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                     /* else fall thru ... */
 #endif
                   case TOK_STRING:
-                    pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+                    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, NULL,
+                    if (!js_ReportCompileErrorNumber(cx, ts,
+                                                     JSREPORT_TS |
                                                      JSREPORT_WARNING |
                                                      JSREPORT_STRICT,
                                                      JSMSG_TRAILING_COMMA)) {
@@ -2967,7 +3958,8 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                     }
                     goto end_obj_init;
                   default:
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_BAD_PROP_ID);
                     return NULL;
                 }
@@ -2981,7 +3973,8 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
                 }
 #endif
                 if (tt != TOK_COLON) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_COLON_AFTER_ID);
                     return NULL;
                 }
@@ -3006,7 +3999,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
       case TOK_DEFSHARP:
         if (defsharp)
             goto badsharp;
-        defsharp = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        defsharp = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!defsharp)
             return NULL;
         defsharp->pn_kid = NULL;
@@ -3015,7 +4008,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 
       case TOK_USESHARP:
         /* Check for forward/dangling references at runtime, to allow eval. */
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+        pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
         pn->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
@@ -3025,26 +4018,10 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 #endif /* JS_HAS_INITIALIZERS */
 
       case TOK_LP:
-      {
-#if JS_HAS_IN_OPERATOR
-        uintN oldflags;
-#endif
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+        pn = NewParseNode(cx, ts, PN_UNARY, tc);
         if (!pn)
             return NULL;
-#if JS_HAS_IN_OPERATOR
-        /*
-         * Always accept the 'in' operator in a parenthesized expression,
-         * where it's unambiguous, even if we might be parsing the init of a
-         * for statement.
-         */
-        oldflags = tc->flags;
-        tc->flags &= ~TCF_IN_FOR_INIT;
-#endif
-        pn2 = Expr(cx, ts, tc);
-#if JS_HAS_IN_OPERATOR
-        tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
-#endif
+        pn2 = BracketedExpr(cx, ts, tc);
         if (!pn2)
             return NULL;
 
@@ -3053,26 +4030,68 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         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;
-#endif
         /* 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, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+        pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
-        pn->pn_op = CURRENT_TOKEN(ts).t_op;
         pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
+#if 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) {
@@ -3102,7 +4121,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         break;
 
       case TOK_NUMBER:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+        pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
         pn->pn_dval = CURRENT_TOKEN(ts).t_dval;
@@ -3112,7 +4131,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
         break;
 
       case TOK_PRIMARY:
-        pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc);
+        pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
         pn->pn_op = CURRENT_TOKEN(ts).t_op;
@@ -3125,21 +4144,12 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
       case TOK_EXPORT:
       case TOK_IMPORT:
 #endif
-      case TOK_RESERVED:
-        badWord = js_DeflateString(cx, CURRENT_TOKEN(ts).ptr,
-                                   (size_t) CURRENT_TOKEN(ts).pos.end.index
-                                          - CURRENT_TOKEN(ts).pos.begin.index);
-        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
-                                    JSMSG_RESERVED_ID, badWord);
-        JS_free(cx, badWord);
-        return NULL;
-
       case TOK_ERROR:
         /* The scanner or one of its subroutines reported the error. */
         return NULL;
 
       default:
-        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_SYNTAX_ERROR);
         return NULL;
     }
@@ -3148,7 +4158,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
     if (defsharp) {
         if (notsharp) {
   badsharp:
-            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_BAD_SHARP_VAR_DEF);
             return NULL;
         }
@@ -3329,6 +4339,157 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
     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)
 {
@@ -3342,11 +4503,61 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
 
     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))
@@ -3485,13 +4696,11 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
             }
 
             /* Fill the buffer, advancing chars and recycling kids as we go. */
-            for (pn2 = pn1; pn2; pn2 = pn3) {
+            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;
-                pn3 = pn2->pn_next;
-                RecycleTree(pn2, tc);
             }
             *chars = 0;
 
@@ -3628,6 +4837,42 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *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:;
     }
 
index 9ce12b3916c007079c014a603aabcd4bf704df5a..24b27bdc1265f45ed2ff5d468663af86ba502f6e 100644 (file)
@@ -42,6 +42,7 @@
 /*
  * JS parser definitions.
  */
+#include "jsconfig.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsscan.h"
@@ -155,8 +156,8 @@ JS_BEGIN_EXTERN_C
  *                          pn_count: 1 + N (where N is number of args)
  *                          ctor is a MEMBER expr
  * TOK_DELETE   unary       pn_kid: MEMBER expr
- * TOK_DOT      name        pn_expr: MEMBER expr to left of .
- *                          pn_atom: name to right of .
+ * TOK_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
@@ -182,6 +183,58 @@ JS_BEGIN_EXTERN_C
  *                          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:
+ *
+ *    <name1{expr1} name2{expr2}name3={expr3}>
+ *
+ * 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:
+ *
+ *    <a x={x}>Hi there!<b y={y}>How are you?</b><answer>{x + y}</answer></a>
+ *
+ * translates to:
+ *
+ *    ((a x {x}) 'Hi there!' ((b y {y}) 'How are you?') ((answer) {x + y}))
  */
 typedef enum JSParseNodeArity {
     PN_FUNC     = -3,
@@ -194,11 +247,11 @@ typedef enum JSParseNodeArity {
 } JSParseNodeArity;
 
 struct JSParseNode {
-    JSTokenType         pn_type;
+    uint16              pn_type;
+    uint8               pn_op;
+    int8                pn_arity;
     JSTokenPos          pn_pos;
-    JSOp                pn_op;
     ptrdiff_t           pn_offset;      /* first generated bytecode offset */
-    JSParseNodeArity    pn_arity;
     union {
         struct {                        /* TOK_FUNCTION node */
             JSAtom      *funAtom;       /* atomized function object */
@@ -232,9 +285,16 @@ struct JSParseNode {
             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
@@ -258,6 +318,7 @@ struct JSParseNode {
 #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 */
@@ -266,6 +327,7 @@ struct JSParseNode {
 #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
@@ -304,7 +366,7 @@ struct JSParseNode {
     JS_BEGIN_MACRO                                                            \
         (list)->pn_head = NULL;                                               \
         (list)->pn_tail = &(list)->pn_head;                                   \
-        (list)->pn_count = 0;                                                 \
+        (list)->pn_count = (list)->pn_extra = 0;                              \
     JS_END_MACRO
 
 #define PN_INIT_LIST_1(list, pn)                                              \
@@ -312,6 +374,7 @@ struct JSParseNode {
         (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)                                                   \
@@ -340,6 +403,12 @@ 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___ */
index 591313ef7c76e02cf29661393d2424a8ed6f1a02..ba7c0f03b4ea8177369e7567c576162785bfed6f 100644 (file)
@@ -49,6 +49,8 @@
 #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,
@@ -105,6 +107,7 @@ struct NumArgState{
 #define TYPE_STRING     8
 #define TYPE_DOUBLE     9
 #define TYPE_INTSTR     10
+#define TYPE_WSTRING    11
 #define TYPE_UNKNOWN    20
 
 #define FLAG_LEFT       0x1
@@ -395,6 +398,27 @@ static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
     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,
@@ -578,7 +602,7 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
             break;
 
         case 's':
-            nas[ cn ].type = TYPE_STRING;
+            nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
             break;
 
         case 'n':
@@ -635,6 +659,8 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv,
 
         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;
@@ -662,11 +688,13 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
     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;
@@ -678,7 +706,10 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
     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
@@ -905,7 +936,6 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
             break;
 
           case 'c':
-            u.ch = va_arg(ap, int);
             if ((flags & FLAG_LEFT) == 0) {
                 while (width-- > 1) {
                     rv = (*ss->stuff)(ss, " ", 1);
@@ -914,7 +944,20 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
                     }
                 }
             }
-            rv = (*ss->stuff)(ss, &u.ch, 1);
+            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;
             }
@@ -953,8 +996,17 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
 #endif
 
           case 's':
-            u.s = va_arg(ap, const char*);
-            rv = cvt_s(ss, u.s, width, prec, flags);
+            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;
             }
index e8cc46c0cd1ea8914cf2d303f2e1f9799db629a2..0eb910f279dbc8eb6ed690ba77427dc4edad33f0 100644 (file)
 
 /*
 ** API for PR printf like routines. Supports the following formats
-**     %d - decimal
-**     %u - unsigned decimal
-**     %x - unsigned hex
-**     %X - unsigned uppercase hex
-**     %o - unsigned octal
-**     %hd, %hu, %hx, %hX, %ho - 16-bit versions of above
-**     %ld, %lu, %lx, %lX, %lo - 32-bit versions of above
-**     %lld, %llu, %llx, %llX, %llo - 64 bit versions of above
-**     %s - string
-**     %c - character
-**     %p - pointer (deals with machine dependent pointer size)
-**     %f - float
-**     %g - float
+**      %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 <stdio.h>
index f5f1e77f60126e70859438dbaeab387fb2e40d7c..ed12f1bde5b66683d6adabac46a6df8b76a82d68 100644 (file)
 
 #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;
@@ -92,7 +118,13 @@ 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 {
@@ -104,8 +136,8 @@ typedef enum JSTrapStatus {
 } JSTrapStatus;
 
 typedef JSTrapStatus
-(* JS_DLL_CALLBACK JSTrapHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, 
-                                  jsval *rval, void *closure);
+(* 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,
@@ -115,56 +147,53 @@ typedef JSBool
 typedef void
 (* JS_DLL_CALLBACK JSNewScriptHook)(JSContext  *cx,
                                     const char *filename,  /* URL of script */
-                                    uintN      lineno,     /* line script starts */
+                                    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, 
+(* 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, 
+(* JS_DLL_CALLBACK JSSourceHandler)(const char *filename, uintN lineno,
+                                    jschar *str, size_t length,
                                     void **listenerTSData, void *closure);
 
 /*
-* This hook captures high level script execution and function calls
-* (JS or native). 
-* It is used by JS_SetExecuteHook to hook top level scripts and by
-* JS_SetCallHook to hook function calls.
-* It will get called twice per script or function call:
-* just before execution begins and just after it finishes. In both cases
-* the 'current' frame is that of the executing code.
-*
-* The 'before' param is JS_TRUE for the hook invocation before the execution
-* and JS_FALSE for the invocation after the code has run.
-*
-* The 'ok' param is significant only on the post execution invocation to
-* signify whether or not the code completed 'normally'.
-*
-* The 'closure' param is as passed to JS_SetExecuteHook or JS_SetCallHook 
-* for the 'before'invocation, but is whatever value is returned from that 
-* invocation for the 'after' invocation. Thus, the hook implementor *could*
-* allocate a stucture in the 'before' invocation and return a pointer
-* to that structure. The pointer would then be handed to the hook for
-* the 'after' invocation. Alternately, the 'before' could just return the
-* same value as in 'closure' to cause the 'after' invocation to be called 
-* with the same 'closure' value as the 'before'.
-*
-* Returning NULL in the 'before' hook will cause the 'after' hook to
-* NOT be called.
-*/
-
+ * 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, 
+(* JS_DLL_CALLBACK JSObjectHook)(JSContext *cx, JSObject *obj, JSBool isNew,
                                  void *closure);
 
 typedef JSBool
index 5f19a15ce71cbfa5ab5701431646d91677498efe..e9da9278303b6ef2f29427d34ee8ad661e004b71 100644 (file)
@@ -69,6 +69,7 @@ typedef enum JSVersion {
     JSVERSION_1_4     = 140,
     JSVERSION_ECMA_3  = 148,
     JSVERSION_1_5     = 150,
+    JSVERSION_1_6     = 160,
     JSVERSION_DEFAULT = 0,
     JSVERSION_UNKNOWN = -1
 } JSVersion;
@@ -84,6 +85,8 @@ typedef enum JSType {
     JSTYPE_STRING,              /* string */
     JSTYPE_NUMBER,              /* number */
     JSTYPE_BOOLEAN,             /* boolean */
+    JSTYPE_NULL,                /* null */
+    JSTYPE_XML,                 /* xml object */
     JSTYPE_LIMIT
 } JSType;
 
@@ -112,6 +115,7 @@ typedef enum JSIterateOp {
 
 /* Struct typedefs. */
 typedef struct JSClass           JSClass;
+typedef struct JSExtendedClass   JSExtendedClass;
 typedef struct JSConstDoubleSpec JSConstDoubleSpec;
 typedef struct JSContext         JSContext;
 typedef struct JSErrorReport     JSErrorReport;
@@ -123,11 +127,12 @@ 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 JSRuntime         JSTaskState;   /* XXX deprecated name */
 typedef struct JSScript          JSScript;
 typedef struct JSString          JSString;
-typedef struct JSXDRState       JSXDRState;
+typedef struct JSXDRState        JSXDRState;
 typedef struct JSExceptionState  JSExceptionState;
 typedef struct JSLocaleCallbacks JSLocaleCallbacks;
 
@@ -203,6 +208,9 @@ typedef JSBool
  *
  *  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,
@@ -263,12 +271,17 @@ typedef void
  * 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.
+ * 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);
@@ -387,11 +400,7 @@ typedef void
  */
 typedef JSBool
 (* JS_DLL_CALLBACK JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id,
-                                   JSObject **objp, JSProperty **propp
-#if defined JS_THREADSAFE && defined DEBUG
-                                 , const char *file, uintN line
-#endif
-                                  );
+                                   JSObject **objp, JSProperty **propp);
 
 /*
  * Define obj[id], a direct property of obj named id, having the given initial
@@ -491,6 +500,27 @@ 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
@@ -517,13 +547,19 @@ typedef void
                                     JSErrorReport *report);
 
 typedef struct JSErrorFormatString {
+    /* The error format string (UTF-8 if JS_C_STRINGS_ARE_UTF8 is defined). */
     const char *format;
-    uintN argCount;
+
+    /* 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);
+                                    const uintN errorNumber);
 
 #ifdef va_start
 #define JS_ARGUMENT_FORMATTER_DEFINED 1
index 4d909d4e28403722bc0d0a94759729ac0e088fb7..e9400eb09ce0b80033b12ae35a368be3073b8de1 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
 #include "jsscan.h"
 #include "jsstr.h"
 
-#ifdef XP_MAC
-#include <MacMemory.h>
-#endif
-
 #if JS_HAS_REGEXPS
 
 /* Note : contiguity of 'simple opcodes' is important for SimpleMatch() */
@@ -137,22 +134,22 @@ struct RENode {
     union {
         void        *kid2;      /* second operand */
         jsint       num;        /* could be a number */
-        uint16      parenIndex; /* or a parenthesis index */
+        size_t      parenIndex; /* or a parenthesis index */
         struct {                /* or a quantifier range */
-            uint16  min;
-            uint16  max;
-            JSBool  greedy;
+            uintN  min;
+            uintN  max;
+            JSPackedBool greedy;
         } range;
         struct {                /* or a character class */
-            uint16  startIndex;
-            uint16  kidlen;     /* length of string at kid, in jschars */
+            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 */
-            uint16  index;      /* index into class list */
-            JSBool  sense;
+            JSPackedBool sense;
         } ucclass;
         struct {                /* or a literal sequence */
             jschar  chr;        /* of one character */
-            uint16  length;     /* or many (via the kid) */
+            size_t  length;     /* or many (via the kid) */
         } flat;
         struct {
             RENode  *kid2;      /* second operand from ALT */
@@ -175,29 +172,118 @@ typedef struct CompilerState {
     const jschar    *cpbegin;
     const jschar    *cpend;
     const jschar    *cp;
-    uint16          flags;
-    uint16          parenCount;
-    uint16          classCount;   /* number of [] encountered */
-    uint16          treeDepth;    /* maximum depth of parse tree */
+    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 */
-        uint16 length;              /* since they're often the same */
-        uint16 index;
+        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 {
-    int32 index;               /* start of contents, -1 for empty  */
-    uint16 length;             /* length of capture */
+    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.
-                               */
+                                 allocated at end of this struct */
 } REMatchState;
 
 struct REBackTrackData;
@@ -205,12 +291,12 @@ struct REBackTrackData;
 typedef struct REProgState {
     jsbytecode *continue_pc;        /* current continuation data */
     jsbytecode continue_op;
-    uint16 index;                   /* progress in text */
-    uintN parenSoFar;               /* highest indexed paren started */
+    ptrdiff_t index;                /* progress in text */
+    size_t parenSoFar;              /* highest indexed paren started */
     union {
         struct {
-            uint16 min;             /* current quantifier limits */
-            uint16 max;
+            uintN min;             /* current quantifier limits */
+            uintN max;
         } quantifier;
         struct {
             size_t top;             /* backtrack stack state */
@@ -224,15 +310,15 @@ typedef struct REBackTrackData {
     jsbytecode *backtrack_pc;       /* where to backtrack to */
     jsbytecode backtrack_op;
     const jschar *cp;               /* index in text of match at backtrack */
-    uint16 parenIndex;              /* start index of saved paren contents */
-    uint16 parenCount;              /* # of saved paren contents */
-    uint16 saveStateStackTop;       /* number of parent states */
+    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)
+#define INITIAL_STATESTACK  100
+#define INITIAL_BACKTRACK   8000
 
 typedef struct REGlobalData {
     JSContext *cx;
@@ -240,25 +326,23 @@ typedef struct REGlobalData {
     JSBool ok;                      /* runtime error (out_of_memory only?) */
     size_t start;                   /* offset to start at */
     ptrdiff_t skipped;              /* chars skipped anchoring this r.e. */
-    const jschar *cpbegin, *cpend;  /* text base address and limit */
+    const jschar    *cpbegin;       /* text base address */
+    const jschar    *cpend;         /* text limit address */
 
     REProgState *stateStack;        /* stack of state of current parents */
-    uint16 stateStackTop;
-    uint16 stateStackLimit;
+    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;               /* I don't understand but it's faster to
-                                     * use this than to malloc/free the three
-                                     * items that are allocated from this pool
-                                     */
-
+    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
@@ -332,7 +416,7 @@ isASCIIHexDigit(jschar c, uintN *digit)
 typedef struct {
     REOp op;
     const jschar *errPos;
-    uint16 parenIndex;
+    size_t parenIndex;
 } REOpData;
 
 
@@ -341,7 +425,8 @@ typedef struct {
  * operand in the penultimate slot. Update progLength and treeDepth.
  */
 static JSBool
-ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack, intN operandSP)
+ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack,
+          intN operandSP)
 {
     RENode *result;
 
@@ -353,11 +438,19 @@ ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack, intN op
         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
+         * Look at both alternates to see if there's a FLAT or a CLASS at
+         * the start of each. If so, use a prerequisite match.
          */
-        ++state->treeDepth;
         if (((RENode *) result->kid)->op == REOP_FLAT &&
             ((RENode *) result->u.kid2)->op == REOP_FLAT &&
             (state->flags & JSREG_FOLD) == 0) {
@@ -393,25 +486,29 @@ ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack, intN op
                                           JUMP, <end> ... ENDALT */
             state->progLength += 13;
         }
-        else
+        else {
             /* ALT, <next>, ..., JUMP, <end> ... ENDALT */
             state->progLength += 7;
+        }
         break;
+
     case REOP_CONCAT:
         result = operandStack[operandSP - 2];
         while (result->next)
             result = result->next;
         result->next = operandStack[operandSP - 1];
         break;
+
     case REOP_ASSERT:
     case REOP_ASSERT_NOT:
     case REOP_LPARENNON:
     case REOP_LPAREN:
         /* These should have been processed by a close paren. */
-        js_ReportCompileErrorNumber(state->context, state->tokenStream,
-                                    NULL, JSREPORT_ERROR,
-                                    JSMSG_MISSING_PAREN, opData->errPos);
+        js_ReportCompileErrorNumberUC(state->context, state->tokenStream,
+                                      JSREPORT_TS | JSREPORT_ERROR,
+                                      JSMSG_MISSING_PAREN, opData->errPos);
         return JS_FALSE;
+
     default:;
     }
     return JS_TRUE;
@@ -422,6 +519,7 @@ ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack, intN op
  */
 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.
@@ -434,7 +532,7 @@ static JSBool ParseQuantifier(CompilerState *state);
 static JSBool
 ParseRegExp(CompilerState *state)
 {
-    uint16 parenIndex;
+    size_t parenIndex;
     RENode *operand;
     REOpData *operatorStack;
     RENode **operandStack;
@@ -461,7 +559,7 @@ ParseRegExp(CompilerState *state)
     if (!operandStack)
         goto out;
 
-    while (JS_TRUE) {
+    for (;;) {
         parenIndex = state->parenCount;
         if (state->cp == state->cpend) {
             /*
@@ -477,8 +575,7 @@ ParseRegExp(CompilerState *state)
             }
         } else {
             switch (*state->cp) {
-                /* balance '(' */
-            case '(':           /* balance ')' */
+            case '(':
                 ++state->cp;
                 if (state->cp + 1 < state->cpend &&
                     *state->cp == '?' &&
@@ -504,26 +601,30 @@ ParseRegExp(CompilerState *state)
                 } else {
                     op = REOP_LPAREN;
                     /* LPAREN, <index>, ... RPAREN, <index> */
-                    state->progLength += 6;
+                    state->progLength
+                        += 2 * (1 + GetCompactIndexWidth(parenIndex));
                     state->parenCount++;
                     if (state->parenCount == 65535) {
                         js_ReportCompileErrorNumber(state->context,
                                                     state->tokenStream,
-                                                    NULL, JSREPORT_ERROR,
+                                                    JSREPORT_TS |
+                                                    JSREPORT_ERROR,
                                                     JSMSG_TOO_MANY_PARENS);
                         goto out;
                     }
                 }
                 goto pushOperator;
+
             case ')':
-                /* If there's not a stacked open parenthesis, throw
-                 * a syntax error.
+                /*
+                 * If there's no stacked open parenthesis, throw syntax error.
                  */
                 for (i = operatorSP - 1; ; i--) {
                     if (i < 0) {
                         js_ReportCompileErrorNumber(state->context,
                                                     state->tokenStream,
-                                                    NULL, JSREPORT_ERROR,
+                                                    JSREPORT_TS |
+                                                    JSREPORT_ERROR,
                                                     JSMSG_UNMATCHED_RIGHT_PAREN);
                         goto out;
                     }
@@ -534,13 +635,15 @@ ParseRegExp(CompilerState *state)
                         break;
                     }
                 }
-                /* fall thru... */
+                /* 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;
@@ -548,9 +651,9 @@ ParseRegExp(CompilerState *state)
 pushOperand:
                 if (operandSP == operandStackSize) {
                     operandStackSize += operandStackSize;
-                    operandStack =
-                      (RENode **)JS_realloc(state->context, operandStack,
-                                            sizeof(RENode *) * operandStackSize);
+                    operandStack = (RENode **)
+                        JS_realloc(state->context, operandStack,
+                                   sizeof(RENode *) * operandStackSize);
                     if (!operandStack)
                         goto out;
                 }
@@ -558,7 +661,8 @@ pushOperand:
                 break;
             }
         }
-            /* At the end; process remaining operators */
+
+        /* At the end; process remaining operators. */
 restartOperator:
         if (state->cp == state->cpend) {
             while (operatorSP) {
@@ -573,6 +677,7 @@ restartOperator:
             result = JS_TRUE;
             goto out;
         }
+
         switch (*state->cp) {
         case '|':
             /* Process any stacked 'concat' operators */
@@ -581,22 +686,23 @@ restartOperator:
                    operatorStack[operatorSP - 1].op == REOP_CONCAT) {
                 --operatorSP;
                 if (!ProcessOp(state, &operatorStack[operatorSP],
-                               operandStack, operandSP))
+                               operandStack, operandSP)) {
                     goto out;
+                }
                 --operandSP;
             }
             op = REOP_ALT;
             goto pushOperator;
 
         case ')':
-            /* If there's not a stacked open parenthesis,we
-             * accept the close as a flat.
+            /*
+             * If there's no stacked open parenthesis, throw syntax error.
              */
             for (i = operatorSP - 1; ; i--) {
                 if (i < 0) {
                     js_ReportCompileErrorNumber(state->context,
                                                 state->tokenStream,
-                                                NULL, JSREPORT_ERROR,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_UNMATCHED_RIGHT_PAREN);
                     goto out;
                 }
@@ -608,8 +714,9 @@ restartOperator:
                 }
             }
             ++state->cp;
-            /* process everything on the stack until the open */
-            while (JS_TRUE) {
+
+            /* Process everything on the stack until the open parenthesis. */
+            for (;;) {
                 JS_ASSERT(operatorSP);
                 --operatorSP;
                 switch (operatorStack[operatorSP].op) {
@@ -624,8 +731,17 @@ restartOperator:
                     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 thru... */
+                    /* FALL THROUGH */
+
                 case REOP_LPARENNON:
                     state->result = operandStack[operandSP - 1];
                     if (!ParseQuantifier(state))
@@ -641,24 +757,42 @@ restartOperator:
                 }
             }
             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 '?':
-        case '{':
-            js_ReportCompileErrorNumber(state->context, state->tokenStream,
-                                        NULL, JSREPORT_ERROR,
-                                        JSMSG_BAD_QUANTIFIER, state->cp);
+            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 */
+            /* 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);
+                operatorStack = (REOpData *)
+                    JS_realloc(state->context, operatorStack,
+                               sizeof(REOpData) * operatorStackSize);
                 if (!operatorStack)
                     goto out;
             }
@@ -712,6 +846,7 @@ FindParenCount(CompilerState *state)
     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;
 
@@ -998,7 +1133,7 @@ ParseTerm(CompilerState *state)
         if (state->cp >= state->cpend) {
             /* a trailing '\' is an error */
             js_ReportCompileErrorNumber(state->context, state->tokenStream,
-                                        NULL, JSREPORT_ERROR,
+                                        JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_TRAILING_SLASH);
             return JS_FALSE;
         }
@@ -1019,31 +1154,28 @@ ParseTerm(CompilerState *state)
             return JS_TRUE;
         /* Decimal escape */
         case '0':
-            if (JS_HAS_STRICT_OPTION(state->context)) {
-                if (!js_ReportCompileErrorNumber(state->context,
-                                                 state->tokenStream,
-                                                 NULL,
-                                                 JSREPORT_WARNING |
-                                                 JSREPORT_STRICT,
-                                                 JSMSG_INVALID_BACKREF)) {
-                    return JS_FALSE;
-                }
-                c = 0;
-            } else {
+            /* 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;
+            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)
@@ -1066,13 +1198,10 @@ ParseTerm(CompilerState *state)
             if (state->flags & JSREG_FIND_PAREN_ERROR)
                 return JS_FALSE;
             if (num == OVERFLOW_VALUE) {
-                if (!JS_HAS_STRICT_OPTION(state->context)) {
-                    state->cp = termStart;
-                    goto doOctal;
-                }
+                /* Give a strict mode warning. */
                 if (!js_ReportCompileErrorNumber(state->context,
                                                  state->tokenStream,
-                                                 NULL,
+                                                 JSREPORT_TS |
                                                  JSREPORT_WARNING |
                                                  JSREPORT_STRICT,
                                                  (c >= '8')
@@ -1080,14 +1209,30 @@ ParseTerm(CompilerState *state)
                                                  : JSMSG_BAD_BACKREF)) {
                     return JS_FALSE;
                 }
-                num = 0x10000;
+
+                /*
+                 * 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 += 3;
+            state->progLength
+                += 1 + GetCompactIndexWidth(state->result->u.parenIndex);
             break;
         /* Control escape */
         case 'f':
@@ -1129,8 +1274,8 @@ lexHex:
                 c = *state->cp++;
                 if (!isASCIIHexDigit(c, &digit)) {
                     /*
-                     *  back off to accepting the original
-                     *  'u' or 'x' as a literal
+                     * Back off to accepting the original 'u' or 'x' as a
+                     * literal.
                      */
                     state->cp -= i + 2;
                     n = *state->cp++;
@@ -1181,20 +1326,23 @@ doSimple:
             return JS_FALSE;
         termStart = state->cp;
         state->result->u.ucclass.startIndex = termStart - state->cpbegin;
-        while (JS_TRUE) {
+        for (;;) {
             if (state->cp == state->cpend) {
-                js_ReportCompileErrorNumber(state->context, state->tokenStream,
-                                            NULL, JSREPORT_ERROR,
-                                            JSMSG_UNTERM_CLASS, termStart);
+                js_ReportCompileErrorNumberUC(state->context, state->tokenStream,
+                                              JSREPORT_TS | JSREPORT_ERROR,
+                                              JSMSG_UNTERM_CLASS, termStart);
+
                 return JS_FALSE;
             }
             if (*state->cp == '\\') {
                 state->cp++;
-            } else {
-                if (*state->cp == ']') {
-                    state->result->u.ucclass.kidlen = state->cp - termStart;
-                    break;
-                }
+                if (state->cp != state->cpend)
+                    state->cp++;
+                continue;
+            }
+            if (*state->cp == ']') {
+                state->result->u.ucclass.kidlen = state->cp - termStart;
+                break;
             }
             state->cp++;
         }
@@ -1209,8 +1357,8 @@ doSimple:
                 state->result->u.ucclass.kidlen) {
                 for (n = 0; ; n++) {
                     if (n == state->classCache[i].length) {
-                        state->result->u.ucclass.index =
-                            state->classCache[i].index;
+                        state->result->u.ucclass.index
+                            state->classCache[i].index;
                         goto claim;
                     }
                     if (state->classCache[i].start[n] != termStart[n])
@@ -1219,6 +1367,7 @@ doSimple:
             }
         }
         state->result->u.ucclass.index = state->classCount++;
+
     claim:
         /*
          * Call CalculateBitmapSize now as we want any errors it finds
@@ -1226,20 +1375,50 @@ doSimple:
          */
         if (!CalculateBitmapSize(state, state->result, termStart, state->cp++))
             return JS_FALSE;
-        state->progLength += 3; /* CLASS, <index> */
+        /*
+         * 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, <index> */
+        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_ReportCompileErrorNumber(state->context, state->tokenStream,
-                                    NULL, JSREPORT_ERROR,
-                                    JSMSG_BAD_QUANTIFIER, state->cp - 1);
+        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;
@@ -1264,7 +1443,7 @@ ParseQuantifier(CompilerState *state)
             if (!state->result)
                 return JS_FALSE;
             state->result->u.range.min = 1;
-            state->result->u.range.max = (uint16)-1;
+            state->result->u.range.max = (uintN)-1;
             /* <PLUS>, <next> ... <ENDCHILD> */
             state->progLength += 4;
             goto quantifier;
@@ -1273,7 +1452,7 @@ ParseQuantifier(CompilerState *state)
             if (!state->result)
                 return JS_FALSE;
             state->result->u.range.min = 0;
-            state->result->u.range.max = (uint16)-1;
+            state->result->u.range.max = (uintN)-1;
             /* <STAR>, <next> ... <ENDCHILD> */
             state->progLength += 4;
             goto quantifier;
@@ -1287,109 +1466,131 @@ ParseQuantifier(CompilerState *state)
             state->progLength += 4;
             goto quantifier;
         case '{':       /* balance '}' */
-            {
-                intN err;
-                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 (min == OVERFLOW_VALUE) {
-                        err = JSMSG_MIN_TOO_BIG;
-                        goto quantError;
-                    }
-                    if (c == ',') {
-                        c = *++state->cp;
-                        if (JS7_ISDEC(c)) {
-                            ++state->cp;
-                            max = GetDecimalValue(c, 0xFFFF, NULL, state);
-                            c = *state->cp;
-                            if (max == OVERFLOW_VALUE) {
-                                err = JSMSG_MAX_TOO_BIG;
-                                goto quantError;
-                            }
-                            if (min > max) {
-                                err = JSMSG_OUT_OF_ORDER;
-                                goto quantError;
-                            }
-                        } 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, <min>, <max>, <next> ... <ENDCHILD> */
-                        state->progLength += 8;
-                        goto quantifier;
-                    }
-                }
-                state->cp = errp;
+        {
+            intN err;
+            const jschar *errp = state->cp;
+
+            err = ParseMinMaxQuantifier(state, JS_FALSE);
+            if (err == 0)
+                goto quantifier;
+            if (err == -1)
                 return JS_TRUE;
-quantError:
-                js_ReportCompileErrorNumber(state->context,
-                                            state->tokenStream,
-                                            NULL, JSREPORT_ERROR,
-                                            err, errp);
-                return JS_FALSE;
-            }
+
+            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
+    } else {
         state->result->u.range.greedy = JS_TRUE;
+    }
     return JS_TRUE;
 }
 
-#define CHECK_OFFSET(diff) (JS_ASSERT(((diff) >= -32768) && ((diff) <= 32767)))
-#define SET_OFFSET(pc,off) ((pc)[0] = JUMP_OFFSET_HI(off),                     \
-                                 (pc)[1] = JUMP_OFFSET_LO(off))
-#define GET_OFFSET(pc)     ((int16)(((pc)[0] << 8) | (pc)[1]))
-#define OFFSET_LEN         (2)
-#define GET_ARG(pc)        GET_OFFSET(pc)
-#define SET_ARG(pc,arg)    SET_OFFSET(pc,arg)
-#define ARG_LEN            OFFSET_LEN
+static intN
+ParseMinMaxQuantifier(CompilerState *state, JSBool ignoreValues)
+{
+    uintN min, max;
+    jschar c;
+    const jschar *errp = state->cp++;
 
-/*
- * Recursively generate bytecode for the tree rooted at t. Iteratively.
- */
+    c = *state->cp;
+    if (JS7_ISDEC(c)) {
+        ++state->cp;
+        min = GetDecimalValue(c, 0xFFFF, NULL, state);
+        c = *state->cp;
 
-typedef struct {
-    RENode *nextAlt;
-    jsbytecode *nextAltFixup, *nextTermFixup, *endTermFixup;
-    RENode *continueNode;
-    REOp continueOp;
-} EmitStateStackEntry;
+        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, <min>, <max>, <next> ... <ENDCHILD>
+             * where <max> 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, intN treeDepth,
+EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth,
                jsbytecode *pc, RENode *t)
 {
-    ptrdiff_t diff;
+    EmitStateStackEntry *emitStateSP, *emitStateStack;
     RECharSet *charSet;
-    EmitStateStackEntry *emitStateSP, *emitStateStack = NULL;
     REOp op;
 
-    if (treeDepth) {
+    if (treeDepth == 0) {
+        emitStateStack = NULL;
+    } else {
         emitStateStack =
             (EmitStateStackEntry *)JS_malloc(state->context,
                                              sizeof(EmitStateStackEntry) *
@@ -1400,7 +1601,7 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
     emitStateSP = emitStateStack;
     op = t->op;
 
-    while (JS_TRUE) {
+    for (;;) {
         *pc++ = op;
         switch (op) {
         case REOP_EMPTY:
@@ -1410,6 +1611,7 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
         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);
@@ -1417,58 +1619,148 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
             SET_ARG(pc, t->u.altprereq.ch2);
             pc += ARG_LEN;
 
-            emitStateSP->nextAltFixup = pc;    /* address of next alternate */
+            emitStateSP->nextAltFixup = pc;    /* offset to next alternate */
             pc += OFFSET_LEN;
 
             emitStateSP->continueNode = t;
             emitStateSP->continueOp = REOP_JUMP;
+            emitStateSP->jumpToJumpFlag = JS_FALSE;
             ++emitStateSP;
-            JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+            JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth);
             t = (RENode *) t->kid;
             op = t->op;
             continue;
 
         case REOP_JUMP:
-            emitStateSP->nextTermFixup = pc;    /* address of following term */
+            emitStateSP->nextTermFixup = pc;    /* offset to following term */
             pc += OFFSET_LEN;
-            diff = pc - emitStateSP->nextAltFixup;
-            CHECK_OFFSET(diff);
-            SET_OFFSET(emitStateSP->nextAltFixup, diff);
+            if (!SetForwardJumpOffset(emitStateSP->nextAltFixup, pc))
+                goto jump_too_big;
             emitStateSP->continueOp = REOP_ENDALT;
             ++emitStateSP;
-            JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
-            t = (RENode *) t->u.kid2;
+            JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth);
+            t = t->u.kid2;
             op = t->op;
             continue;
 
         case REOP_ENDALT:
-            diff = pc - emitStateSP->nextTermFixup;
-            CHECK_OFFSET(diff);
-            SET_OFFSET(emitStateSP->nextTermFixup, diff);
+            /*
+             * 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) {
-                diff = pc - emitStateSP->endTermFixup;
-                CHECK_OFFSET(diff);
-                SET_OFFSET(emitStateSP->endTermFixup, diff);
+                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->nextAltFixup = pc; /* address of pointer to next alternate */
+            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((emitStateSP - emitStateStack) <= treeDepth);
-            t = (RENode *) t->kid;
+            JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth);
+            t = t->kid;
             op = t->op;
             continue;
 
         case REOP_FLAT:
             /*
-             * Consecutize FLAT's if possible.
+             * 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) {
+            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 ==
@@ -1477,26 +1769,17 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
                     t->next = t->next->next;
                 }
             }
-            if (t->kid && (t->u.flat.length > 1)) {
-                if (state->flags & JSREG_FOLD)
-                    pc[-1] = REOP_FLATi;
-                else
-                    pc[-1] = REOP_FLAT;
-                SET_ARG(pc, (jschar *)t->kid - state->cpbegin);
-                pc += ARG_LEN;
-                SET_ARG(pc, t->u.flat.length);
-                pc += ARG_LEN;
+            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) {
-                if (state->flags & JSREG_FOLD)
-                    pc[-1] = REOP_FLAT1i;
-                else
-                    pc[-1] = REOP_FLAT1;
+                pc[-1] = (state->flags & JSREG_FOLD) ? REOP_FLAT1i : REOP_FLAT1;
                 *pc++ = (jsbytecode) t->u.flat.chr;
             } else {
-                if (state->flags & JSREG_FOLD)
-                    pc[-1] = REOP_UCFLAT1i;
-                else
-                    pc[-1] = REOP_UCFLAT1;
+                pc[-1] = (state->flags & JSREG_FOLD)
+                         ? REOP_UCFLAT1i
+                         : REOP_UCFLAT1;
                 SET_ARG(pc, t->u.flat.chr);
                 pc += ARG_LEN;
             }
@@ -1504,24 +1787,23 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
 
         case REOP_LPAREN:
             JS_ASSERT(emitStateSP);
-            SET_ARG(pc, t->u.parenIndex);
-            pc += ARG_LEN;
+            pc = WriteCompactIndex(pc, t->u.parenIndex);
             emitStateSP->continueNode = t;
             emitStateSP->continueOp = REOP_RPAREN;
             ++emitStateSP;
-            JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+            JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth);
             t = (RENode *) t->kid;
             op = t->op;
             continue;
+
         case REOP_RPAREN:
-            SET_ARG(pc, t->u.parenIndex);
-            pc += ARG_LEN;
+            pc = WriteCompactIndex(pc, t->u.parenIndex);
             break;
 
         case REOP_BACKREF:
-            SET_ARG(pc, t->u.parenIndex);
-            pc += ARG_LEN;
+            pc = WriteCompactIndex(pc, t->u.parenIndex);
             break;
+
         case REOP_ASSERT:
             JS_ASSERT(emitStateSP);
             emitStateSP->nextTermFixup = pc;
@@ -1529,16 +1811,17 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
             emitStateSP->continueNode = t;
             emitStateSP->continueOp = REOP_ASSERTTEST;
             ++emitStateSP;
-            JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+            JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth);
             t = (RENode *) t->kid;
             op = t->op;
             continue;
+
         case REOP_ASSERTTEST:
         case REOP_ASSERTNOTTEST:
-            diff = pc - emitStateSP->nextTermFixup;
-            CHECK_OFFSET(diff);
-            SET_OFFSET(emitStateSP->nextTermFixup, diff);
+            if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc))
+                goto jump_too_big;
             break;
+
         case REOP_ASSERT_NOT:
             JS_ASSERT(emitStateSP);
             emitStateSP->nextTermFixup = pc;
@@ -1546,45 +1829,48 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
             emitStateSP->continueNode = t;
             emitStateSP->continueOp = REOP_ASSERTNOTTEST;
             ++emitStateSP;
-            JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth);
+            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 == (uint16)-1) {
+            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 == (uint16) -1) {
+            } 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;
-                SET_ARG(pc, t->u.range.min);
-                pc += ARG_LEN;
-                SET_ARG(pc, t->u.range.max);
-                pc += ARG_LEN;
+                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((emitStateSP - emitStateStack) <= treeDepth);
+            JS_ASSERT((size_t)(emitStateSP - emitStateStack) <= treeDepth);
             t = (RENode *) t->kid;
             op = t->op;
             continue;
+
         case REOP_ENDCHILD:
-            diff = pc - emitStateSP->nextTermFixup;
-            CHECK_OFFSET(diff);
-            SET_OFFSET(emitStateSP->nextTermFixup, diff);
+            if (!SetForwardJumpOffset(emitStateSP->nextTermFixup, pc))
+                goto jump_too_big;
             break;
+
         case REOP_CLASS:
             if (!t->u.ucclass.sense)
                 pc[-1] = REOP_NCLASS;
-            SET_ARG(pc, t->u.ucclass.index);
-            pc += ARG_LEN;
+            pc = WriteCompactIndex(pc, t->u.ucclass.index);
             charSet = &re->classList[t->u.ucclass.index];
             charSet->converted = JS_FALSE;
             charSet->length = t->u.ucclass.bmsize;
@@ -1592,23 +1878,34 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth,
             charSet->u.src.length = t->u.ucclass.kidlen;
             charSet->sense = t->u.ucclass.sense;
             break;
+
         default:
             break;
         }
+
         t = t->next;
-        if (!t) {
+        if (t) {
+            op = t->op;
+        } else {
             if (emitStateSP == emitStateStack)
                 break;
             --emitStateSP;
             t = emitStateSP->continueNode;
             op = emitStateSP->continueOp;
         }
-        else
-            op = t->op;
     }
+
+  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;
 }
 
 
@@ -1626,37 +1923,40 @@ js_NewRegExp(JSContext *cx, JSTokenStream *ts,
 
     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 + JSSTRING_LENGTH(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;
 
-    len = JSSTRING_LENGTH(str);
-
     if (len != 0 && flat) {
         state.result = NewRENode(&state, REOP_FLAT);
         state.result->u.flat.chr = *state.cpbegin;
-        state.result->u.flat.length = JSSTRING_LENGTH(str);
+        state.result->u.flat.length = len;
         state.result->kid = (void *) state.cpbegin;
-        state.progLength += 5;
+        /* Flat bytecode: REOP_FLAT compact(string_offset) compact(len). */
+        state.progLength += 1 + GetCompactIndexWidth(0)
+                          + GetCompactIndexWidth(len);
     } else {
         if (!ParseRegExp(&state))
             goto out;
     }
-    resize = sizeof *re + state.progLength + 1;
-    re = (JSRegExp *) JS_malloc(cx, JS_ROUNDUP(resize, sizeof(jsword)));
+    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 *)
@@ -1676,7 +1976,19 @@ js_NewRegExp(JSContext *cx, JSTokenStream *ts,
         goto out;
     }
     *endPC++ = REOP_END;
-    JS_ASSERT(endPC <= (re->program + (state.progLength + 1)));
+    /*
+     * 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;
@@ -1714,7 +2026,8 @@ js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts,
             default:
                 charBuf[0] = (char)s[i];
                 charBuf[1] = '\0';
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_BAD_FLAG, charBuf);
                 return NULL;
             }
@@ -1723,10 +2036,6 @@ js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts,
     return js_NewRegExp(cx, ts, str, flags, flat);
 }
 
-
-#define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs)
-#define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re)
-
 /*
  * Save the current state of the match - the position in the input
  * text as well as the position in the bytecode. The state of any
@@ -1736,9 +2045,9 @@ js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts,
 static REBackTrackData *
 PushBackTrackState(REGlobalData *gData, REOp op,
                    jsbytecode *target, REMatchState *x, const jschar *cp,
-                   uintN parenIndex, intN parenCount)
+                   size_t parenIndex, size_t parenCount)
 {
-    intN i;
+    size_t i;
     REBackTrackData *result =
         (REBackTrackData *) ((char *)gData->backTrackSP + gData->cursz);
 
@@ -1775,15 +2084,13 @@ PushBackTrackState(REGlobalData *gData, REOp op,
     memcpy(result + 1, gData->stateStack,
            sizeof(REProgState) * result->saveStateStackTop);
 
-    /* FIXME: parenCount should be uintN */
-    JS_ASSERT(parenCount >= 0);
-    if (parenCount > 0) {
+    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++)
+        for (i = 0; i != parenCount; i++)
             x->parens[parenIndex + i].index = -1;
     }
 
@@ -1797,12 +2104,12 @@ PushBackTrackState(REGlobalData *gData, REOp op,
 #if 0
 static REMatchState *
 FlatNMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
-             intN length)
+             size_t length)
 {
-    intN i;
-    if (x->cp + length > gData->cpend)
+    size_t i;
+    if (length > gData->cpend - x->cp)
         return NULL;
-    for (i = 0; i < length; i++) {
+    for (i = 0; i != length; i++) {
         if (matchChars[i] != x->cp[i])
             return NULL;
     }
@@ -1813,12 +2120,13 @@ FlatNMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
 
 static REMatchState *
 FlatNIMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
-              intN length)
+              size_t length)
 {
-    intN i;
-    if (x->cp + length > gData->cpend)
+    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++) {
+    for (i = 0; i != length; i++) {
         if (upcase(matchChars[i]) != upcase(x->cp[i]))
             return NULL;
     }
@@ -1850,20 +2158,20 @@ FlatNIMatcher(REGlobalData *gData, REMatchState *x, jschar *matchChars,
  *     10. Call c(y) and return its result.
  */
 static REMatchState *
-BackrefMatcher(REGlobalData *gData, REMatchState *x, uintN parenIndex)
+BackrefMatcher(REGlobalData *gData, REMatchState *x, size_t parenIndex)
 {
-    uintN len;
-    uintN i;
+    size_t len, i;
     const jschar *parenContent;
-    RECapture *s = &x->parens[parenIndex];
-    if (s->index == -1)
+    RECapture *cap = &x->parens[parenIndex];
+
+    if (cap->index == -1)
         return x;
 
-    len = s->length;
+    len = cap->length;
     if (x->cp + len > gData->cpend)
         return NULL;
 
-    parenContent = &gData->cpbegin[s->index];
+    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]))
@@ -1918,10 +2226,7 @@ AddCharacterRangeToCharSet(RECharSet *cs, jschar c1, jschar c2)
 static JSBool
 ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
 {
-    const jschar *src = JSSTRING_CHARS(gData->regexp->source) +
-                        charSet->u.src.startIndex;
-    const jschar *end = src + charSet->u.src.length;
-
+    const jschar *src, *end;
     JSBool inRange = JS_FALSE;
     jschar rangeStart = 0;
     uintN byteLength, n;
@@ -1929,7 +2234,21 @@ ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
     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);
@@ -1943,10 +2262,9 @@ ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
     if (*src == '^') {
         JS_ASSERT(charSet->sense == JS_FALSE);
         ++src;
-    }
-    else
+    } else {
         JS_ASSERT(charSet->sense == JS_TRUE);
-
+    }
 
     while (src != end) {
         switch (*src) {
@@ -2015,7 +2333,6 @@ ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
                  *  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;
@@ -2125,7 +2442,7 @@ js_DestroyRegExp(JSContext *cx, JSRegExp *re)
 static JSBool
 ReallocStateStack(REGlobalData *gData)
 {
-    uint16 limit = gData->stateStackLimit;
+    size_t limit = gData->stateStackLimit;
     size_t sz = sizeof(REProgState) * limit;
 
     JS_ARENA_GROW_CAST(gData->stateStack, REProgState *, &gData->pool, sz, sz);
@@ -2157,8 +2474,8 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
 {
     REMatchState *result = NULL;
     jschar matchCh;
-    uintN parenIndex;
-    intN offset, length, index;
+    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;
@@ -2243,18 +2560,19 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
         }
         break;
     case REOP_BACKREF:
-        parenIndex = GET_ARG(pc);
-        pc += ARG_LEN;
+        pc = ReadCompactIndex(pc, &parenIndex);
+        JS_ASSERT(parenIndex < gData->regexp->parenCount);
         result = BackrefMatcher(gData, x, parenIndex);
         break;
     case REOP_FLAT:
-        offset = GET_ARG(pc);
-        pc += ARG_LEN;
-        length = GET_ARG(pc);
-        pc += ARG_LEN;
-        source = JSSTRING_CHARS(gData->regexp->source) + offset;
-        if (x->cp + length <= gData->cpend) {
-            for (index = 0; index < length; index++) {
+        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;
             }
@@ -2270,10 +2588,11 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
         }
         break;
     case REOP_FLATi:
-        offset = GET_ARG(pc);
-        pc += ARG_LEN;
-        length = GET_ARG(pc);
-        pc += ARG_LEN;
+        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;
@@ -2301,8 +2620,8 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
         }
         break;
     case REOP_CLASS:
-        index = GET_ARG(pc);
-        pc += ARG_LEN;
+        pc = ReadCompactIndex(pc, &index);
+        JS_ASSERT(index < gData->regexp->classCount);
         if (x->cp != gData->cpend) {
             charSet = &gData->regexp->classList[index];
             JS_ASSERT(charSet->converted);
@@ -2317,8 +2636,8 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
         }
         break;
     case REOP_NCLASS:
-        index = GET_ARG(pc);
-        pc += ARG_LEN;
+        pc = ReadCompactIndex(pc, &index);
+        JS_ASSERT(index < gData->regexp->classCount);
         if (x->cp != gData->cpend) {
             charSet = &gData->regexp->classList[index];
             JS_ASSERT(charSet->converted);
@@ -2351,14 +2670,13 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
 {
     REMatchState *result = NULL;
     REBackTrackData *backTrackData;
-    intN offset;
     jsbytecode *nextpc;
     REOp nextop;
     RECapture *cap;
     REProgState *curState;
     const jschar *startcp;
-    uintN parenIndex, k;
-    uintN parenSoFar = 0;
+    size_t parenIndex, k;
+    size_t parenSoFar = 0;
 
     jschar matchCh1, matchCh2;
     RECharSet *charSet;
@@ -2390,7 +2708,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
             return NULL;
     }
 
-    while (JS_TRUE) {
+    for (;;) {
         if (REOP_IS_SIMPLE(op)) {
             result = SimpleMatch(gData, x, op, &pc, JS_TRUE);
         } else {
@@ -2469,8 +2787,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
              */
             case REOP_JUMP:
                 --gData->stateStackTop;
-                offset = GET_OFFSET(pc);
-                pc += offset;
+                pc += GET_OFFSET(pc);
                 op = (REOp) *pc++;
                 continue;
 
@@ -2483,18 +2800,27 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                 continue;
 
             case REOP_LPAREN:
-                parenIndex = GET_ARG(pc);
+                pc = ReadCompactIndex(pc, &parenIndex);
+                JS_ASSERT(parenIndex < gData->regexp->parenCount);
                 if (parenIndex + 1 > parenSoFar)
                     parenSoFar = parenIndex + 1;
-                pc += ARG_LEN;
                 x->parens[parenIndex].index = x->cp - gData->cpbegin;
                 x->parens[parenIndex].length = 0;
                 op = (REOp) *pc++;
                 continue;
+
             case REOP_RPAREN:
-                parenIndex = GET_ARG(pc);
-                pc += ARG_LEN;
+                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;
@@ -2519,6 +2845,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                     return NULL;
                 }
                 continue;
+
             case REOP_ASSERT_NOT:
                 nextpc = pc + GET_OFFSET(pc);
                 pc += ARG_LEN;
@@ -2540,6 +2867,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                                         nextpc, x, x->cp, 0, 0))
                     return NULL;
                 continue;
+
             case REOP_ASSERTTEST:
                 --gData->stateStackTop;
                 --curState;
@@ -2551,6 +2879,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                 if (result)
                     result = x;
                 break;
+
             case REOP_ASSERTNOTTEST:
                 --gData->stateStackTop;
                 --curState;
@@ -2569,21 +2898,24 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
 
             case REOP_STAR:
                 curState->u.quantifier.min = 0;
-                curState->u.quantifier.max = (uint16)-1;
+                curState->u.quantifier.max = (uintN)-1;
                 goto quantcommon;
             case REOP_PLUS:
                 curState->u.quantifier.min = 1;
-                curState->u.quantifier.max = (uint16)-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:
-                curState->u.quantifier.min = GET_ARG(pc);
-                pc += ARG_LEN;
-                curState->u.quantifier.max = GET_ARG(pc);
-                pc += ARG_LEN;
+                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);
@@ -2643,7 +2975,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                     }
                     if (curState->u.quantifier.min != 0)
                         curState->u.quantifier.min--;
-                    if (curState->u.quantifier.max != (uint16) -1)
+                    if (curState->u.quantifier.max != (uintN) -1)
                         curState->u.quantifier.max--;
                     if (curState->u.quantifier.max == 0)
                         goto repeatDone;
@@ -2683,21 +3015,24 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
 
             case REOP_MINIMALSTAR:
                 curState->u.quantifier.min = 0;
-                curState->u.quantifier.max = (uint16)-1;
+                curState->u.quantifier.max = (uintN)-1;
                 goto minimalquantcommon;
             case REOP_MINIMALPLUS:
                 curState->u.quantifier.min = 1;
-                curState->u.quantifier.max = (uint16)-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:
-                curState->u.quantifier.min = GET_ARG(pc);
-                pc += ARG_LEN;
-                curState->u.quantifier.max = GET_ARG(pc);
-                pc += ARG_LEN;
+                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;
@@ -2706,7 +3041,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                     curState->continue_op = REOP_MINIMALREPEAT;
                     curState->continue_pc = pc;
                     /* step over <next> */
-                    pc += ARG_LEN;
+                    pc += OFFSET_LEN;
                     op = (REOp) *pc++;
                 } else {
                     if (!PushBackTrackState(gData, REOP_MINIMALREPEAT,
@@ -2727,7 +3062,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                     /*
                      * Non-greedy failure - try to consume another child.
                      */
-                    if (curState->u.quantifier.max == (uint16) -1 ||
+                    if (curState->u.quantifier.max == (uintN) -1 ||
                         curState->u.quantifier.max > 0) {
                         curState->index = x->cp - gData->cpbegin;
                         curState->continue_op = REOP_MINIMALREPEAT;
@@ -2750,7 +3085,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                 }
                 if (curState->u.quantifier.min != 0)
                     curState->u.quantifier.min--;
-                if (curState->u.quantifier.max != (uint16) -1)
+                if (curState->u.quantifier.max != (uintN) -1)
                     curState->u.quantifier.max--;
                 if (curState->u.quantifier.min != 0) {
                     curState->continue_op = REOP_MINIMALREPEAT;
@@ -2783,6 +3118,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
             }
         break_switch:;
         }
+
         /*
          *  If the match failed and there's a backtrack option, take it.
          *  Otherwise this is a complete and utter failure.
@@ -2886,8 +3222,8 @@ InitMatch(JSContext *cx, REGlobalData *gData, JSRegExp *re)
 
     JS_ARENA_ALLOCATE_CAST(result, REMatchState *,
                            &gData->pool,
-                           sizeof(REMatchState)
-                               + (re->parenCount - 1) * sizeof(RECapture));
+                           offsetof(REMatchState, parens)
+                           + re->parenCount * sizeof(RECapture));
     if (!result)
         return NULL;
 
@@ -2952,7 +3288,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
         goto out;
     }
     cp = result->cp;
-    i = PTRDIFF(cp, gData.cpbegin, jschar);
+    i = cp - gData.cpbegin;
     *indexp = i;
     matchlen = i - (start + gData.skipped);
     ep = cp;
@@ -2998,7 +3334,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
             ok = JS_FALSE;
             goto out;
         }
-        DEFVAL(STRING_TO_JSVAL(matchstr), INT_TO_JSVAL(0));
+        DEFVAL(STRING_TO_JSVAL(matchstr), INT_TO_JSID(0));
     }
 
     res = &cx->regExpStatics;
@@ -3027,8 +3363,8 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
                 } else if (morenum >= res->moreLength) {
                     res->moreLength += 10;
                     morepar = (JSSubString*)
-                        JS_realloc(cx, morepar, res->moreLength *
-                                                sizeof(JSSubString));
+                        JS_realloc(cx, morepar,
+                                   res->moreLength * sizeof(JSSubString));
                 }
                 if (!morepar) {
                     cx->newborn[GCX_OBJECT] = NULL;
@@ -3048,7 +3384,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
             if (test)
                 continue;
             if (parsub->index == -1) {
-                ok = js_DefineProperty(cx, obj, INT_TO_JSVAL(num + 1),
+                ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1),
                                        JSVAL_VOID, NULL, NULL,
                                        JSPROP_ENUMERATE, NULL);
             } else {
@@ -3060,7 +3396,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
                     ok = JS_FALSE;
                     goto out;
                 }
-                ok = js_DefineProperty(cx, obj, INT_TO_JSVAL(num + 1),
+                ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1),
                                        STRING_TO_JSVAL(parstr), NULL, NULL,
                                        JSPROP_ENUMERATE, NULL);
             }
@@ -3084,20 +3420,20 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
          * order (so they come after the elements).
          */
         DEFVAL(INT_TO_JSVAL(start + gData.skipped),
-               (jsid)cx->runtime->atomState.indexAtom);
+               ATOM_TO_JSID(cx->runtime->atomState.indexAtom));
         DEFVAL(STRING_TO_JSVAL(str),
-               (jsid)cx->runtime->atomState.inputAtom);
+               ATOM_TO_JSID(cx->runtime->atomState.inputAtom));
     }
 
 #undef DEFVAL
 
     res->lastMatch.chars = cp;
     res->lastMatch.length = matchlen;
-    if (cx->version == JSVERSION_1_2) {
+    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"
-         * psuedo-context.  On "hi there bye", the following would result:
+         * pseudo-context.  On "hi there bye", the following would result:
          *
          * Language     while(/ /g){print("$`");}   s/ /$`/g
          * perl4.036    "hi", "there"               "hihitherehi therebye"
@@ -3151,7 +3487,7 @@ regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
     JSRegExp *re;
 
     if (!JSVAL_IS_INT(id))
-       return JS_TRUE;
+        return JS_TRUE;
     slot = JSVAL_TO_INT(id);
     if (slot == REGEXP_LAST_INDEX)
         return JS_GetReservedSlot(cx, obj, 0, vp);
@@ -3159,20 +3495,20 @@ regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *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;
-       }
+        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;
@@ -3187,7 +3523,7 @@ regexp_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
     ok = JS_TRUE;
     if (!JSVAL_IS_INT(id))
-       return ok;
+        return ok;
     slot = JSVAL_TO_INT(id);
     if (slot == REGEXP_LAST_INDEX) {
         if (!js_ValueToNumber(cx, *vp, &lastIndex))
@@ -3433,10 +3769,14 @@ regexp_mark(JSContext *cx, JSObject *obj, void *arg)
 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
+    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};
@@ -3633,7 +3973,7 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
     ok = JS_InstanceOf(cx, obj, &js_RegExpClass, argv);
     if (!ok)
-       return JS_FALSE;
+        return JS_FALSE;
     JS_LOCK_OBJ(cx, obj);
     re = (JSRegExp *) JS_GetPrivate(cx, obj);
     if (!re) {
@@ -3724,7 +4064,7 @@ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
          * TypeError.)  See 10.15.3.1.
          */
         if ((argc < 2 || JSVAL_IS_VOID(argv[1])) &&
-            JSVAL_IS_OBJECT(argv[0]) &&
+            !JSVAL_IS_PRIMITIVE(argv[0]) &&
             OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[0])) == &js_RegExpClass) {
             *rval = argv[0];
             return JS_TRUE;
@@ -3734,6 +4074,12 @@ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         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);
 }
@@ -3776,6 +4122,7 @@ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts,
     JSString *str;
     JSObject *obj;
     JSRegExp *re;
+    JSTempValueRooter tvr;
 
     str = js_NewStringCopyN(cx, chars, length, 0);
     if (!str)
@@ -3783,11 +4130,13 @@ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts,
     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);
-        return NULL;
+        obj = NULL;
     }
+    JS_POP_TEMP_ROOT(cx, &tvr);
     return obj;
 }
 
index 998352df522436a15e474ec5a2be868a2e50e422..50789832d096e0abca4bed21d74e6b2245c6722d 100644 (file)
@@ -65,9 +65,9 @@ struct JSRegExpStatics {
 
 /*
  * 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 
+ * 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 
+ * original regexp source of the beginning of the class contents. The first
  * use of the class converts the source representation into a bitmap.
  *
  */
@@ -78,8 +78,8 @@ typedef struct RECharSet {
     union {
         uint8       *bits;
         struct {
-            uint16  startIndex;
-            uint16  length;
+            size_t  startIndex;
+            size_t  length;
         } src;
     } u;
 } RECharSet;
@@ -102,8 +102,8 @@ struct JSRegExp {
     uint16       flags;         /* flags, see jsapi.h's JSREG_* defines */
     uint16       cloneIndex;    /* index in fp->vars or funobj->slots of
                                    cloned regexp object */
-    uint16       parenCount;    /* number of parenthesized submatches */
-    uint16       classCount;    /* count [...] bitmaps */
+    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 */
@@ -117,6 +117,9 @@ 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);
 
@@ -127,7 +130,7 @@ js_DestroyRegExp(JSContext *cx, JSRegExp *re);
  */
 extern JSBool
 js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
-                JSBool test, jsval *rval);
+                 JSBool test, jsval *rval);
 
 /*
  * These two add and remove GC roots, respectively, so their calls must be
index 995c1e660a6ab64b7034b04ef05f07b4a0e55804..c043799dc05d438f3e6e6866fa487e68739cceeb 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
 #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 */
@@ -79,7 +88,7 @@ static struct keyword {
     {"break",           TOK_BREAK,              JSOP_NOP,   JSVERSION_DEFAULT},
     {"case",            TOK_CASE,               JSOP_NOP,   JSVERSION_DEFAULT},
     {"continue",        TOK_CONTINUE,           JSOP_NOP,   JSVERSION_DEFAULT},
-    {"default",         TOK_DEFAULT,            JSOP_NOP,   JSVERSION_DEFAULT},
+    {js_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},
@@ -96,7 +105,7 @@ static struct keyword {
     {js_this_str,       TOK_PRIMARY,            JSOP_THIS,  JSVERSION_DEFAULT},
     {js_true_str,       TOK_PRIMARY,            JSOP_TRUE,  JSVERSION_DEFAULT},
     {js_typeof_str,     TOK_UNARYOP,            JSOP_TYPEOF,JSVERSION_DEFAULT},
-    {"var",             TOK_VAR,                JSOP_DEFVAR,JSVERSION_DEFAULT},
+    {js_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},
@@ -171,10 +180,13 @@ JSBool
 js_InitScanner(JSContext *cx)
 {
     struct keyword *kw;
+    size_t length;
     JSAtom *atom;
 
     for (kw = keywords; kw->name; kw++) {
-        atom = js_Atomize(cx, kw->name, strlen(kw->name), ATOM_PINNED);
+        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);
@@ -209,6 +221,42 @@ js_NewTokenStream(JSContext *cx, const jschar *base, size_t length,
     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)
 {
@@ -227,6 +275,8 @@ js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length)
     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;
@@ -272,8 +322,8 @@ js_CloseTokenStream(JSContext *cx, JSTokenStream *ts)
     return !ts->file || fclose(ts->file) == 0;
 }
 
-static int
-my_fgets(char *buf, int size, FILE *file)
+JS_FRIEND_API(int)
+js_fgets(char *buf, int size, FILE *file)
 {
     int n, i, c;
     JSBool crflag;
@@ -323,7 +373,7 @@ GetChar(JSTokenStream *ts)
 
                     /* Fill ts->userbuf so that \r and \r\n convert to \n. */
                     crflag = (ts->flags & TSF_CRFLAG) != 0;
-                    len = my_fgets(cbuf, JS_LINE_LIMIT - crflag, ts->file);
+                    len = js_fgets(cbuf, JS_LINE_LIMIT - crflag, ts->file);
                     if (len <= 0) {
                         ts->flags |= TSF_EOF;
                         return EOF;
@@ -479,6 +529,11 @@ PeekChar(JSTokenStream *ts)
     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)
 {
@@ -489,6 +544,10 @@ PeekChars(JSTokenStream *ts, intN n, jschar *cp)
         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--)
@@ -515,37 +574,52 @@ MatchChar(JSTokenStream *ts, int32 expect)
     return JS_FALSE;
 }
 
-JSBool
-js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts,
-                            JSCodeGenerator *cg, uintN flags,
-                            const uintN errorNumber, ...)
+static JSBool
+ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
+                         uintN errorNumber, JSErrorReport *report,
+                         JSBool charArgs, va_list ap)
 {
-    va_list ap;
-    JSErrorReporter onError;
-    JSErrorReport report;
-    jschar *tokenptr;
     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;
 
-    if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
-        return JS_TRUE;
-
-    memset(&report, 0, sizeof (struct JSErrorReport));
-    report.flags = flags;
-    report.errorNumber = errorNumber;
+    memset(report, 0, sizeof (struct JSErrorReport));
+    report->flags = flags;
+    report->errorNumber = errorNumber;
     message = NULL;
 
-    va_start(ap, errorNumber);
     if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL,
-                                 errorNumber, &message, &report, &warning,
-                                 JS_TRUE, ap)) {
+                                 errorNumber, &message, report, &warning,
+                                 charArgs, ap)) {
         return JS_FALSE;
     }
-    va_end(ap);
 
     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) {
@@ -554,30 +628,70 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts,
          * We can be called with null ts from the regexp compilation functions.
          * The code generator (jsemit.c) may pass null ts and non-null cg.
          */
-        if (ts) {
-            report.filename = ts->filename;
-            report.lineno = ts->lineno;
-            linestr = js_NewStringCopyN(cx, ts->linebuf.base,
-                                        ts->linebuf.limit - ts->linebuf.base,
-                                        0);
-            report.linebuf = linestr
-                ? JS_GetStringBytes(linestr)
-                : NULL;
-            tokenptr =
-                ts->tokens[(ts->cursor + ts->lookahead) & NTOKENS_MASK].ptr;
-            report.tokenptr = linestr
-                ? report.linebuf + (tokenptr - ts->linebuf.base)
-                : NULL;
-            report.uclinebuf = linestr
-                ? JS_GetStringChars(linestr)
-                : NULL;
-            report.uctokenptr = linestr
-                ? report.uclinebuf + (tokenptr - ts->linebuf.base)
-                : NULL;
-        } else if (cg) {
-            report.filename = cg->filename;
-            report.lineno = CG_CURRENT_LINE(cg);
-        }
+        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
         /*
@@ -598,54 +712,352 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts,
          */
 
         /*
-         * Only try to raise an exception if there isn't one already set -
-         * otherwise the exception will describe only the last compile error,
+         * 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))
+        if (!ts || !(ts->flags & TSF_ERROR)) {
+            if (js_ErrorToException(cx, message, report))
                 onError = NULL;
+        }
 
         /*
-         * Suppress any compiletime errors that don't occur at the top level.
+         * 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)
+        if (cx->interpLevel != 0 && !JSREPORT_IS_WARNING(flags))
             onError = NULL;
 #endif
-        if (cx->runtime->debugErrorHook && onError) {
+        if (onError) {
             JSDebugErrorHook hook = cx->runtime->debugErrorHook;
-            /* test local in case debugErrorHook changed on another thread */
-            if (hook && !hook(cx, message, &report,
+
+            /*
+             * 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);
+            (*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);
     }
-    if (report.ucmessage)
-        JS_free(cx, (void *)report.ucmessage);
 
-    js_RemoveRoot(cx->runtime, &linestr);
+    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);
 
-    if (ts && !JSREPORT_IS_WARNING(flags)) {
-        /* Set the error flag to suppress spurious reports. */
-        ts->flags |= TSF_ERROR;
-    }
     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)
 {
@@ -666,55 +1078,15 @@ js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts)
     JSTokenType tt;
 
     JS_ASSERT(ts->lookahead == 0 ||
-              ON_CURRENT_LINE(ts, CURRENT_TOKEN(ts).pos));
+              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;
 }
 
-#define TBMIN   64
-
-static JSBool
-GrowTokenBuf(JSContext *cx, JSTokenBuf *tb)
-{
-    jschar *base;
-    ptrdiff_t offset, length;
-    size_t tbsize;
-    JSArenaPool *pool;
-
-    base = tb->base;
-    offset = PTRDIFF(tb->ptr, base, jschar);
-    pool = &cx->tempPool;
-    if (!base) {
-        tbsize = TBMIN * sizeof(jschar);
-        length = TBMIN;
-        JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize);
-    } else {
-        length = PTRDIFF(tb->limit, base, jschar);
-        tbsize = length * sizeof(jschar);
-        length <<= 1;
-        JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize);
-    }
-    if (!base) {
-        JS_ReportOutOfMemory(cx);
-        return JS_FALSE;
-    }
-    tb->base = base;
-    tb->limit = base + length;
-    tb->ptr = base + offset;
-    return JS_TRUE;
-}
-
-static JSBool
-AddToTokenBuf(JSContext *cx, JSTokenBuf *tb, jschar c)
-{
-    if (tb->ptr == tb->limit && !GrowTokenBuf(cx, tb))
-        return JS_FALSE;
-    *tb->ptr++ = c;
-    return JS_TRUE;
-}
-
 /*
  * We have encountered a '\': check for a Unicode escape sequence after it,
  * returning the character code value if we found a Unicode escape sequence.
@@ -741,14 +1113,16 @@ GetUnicodeEscape(JSTokenStream *ts)
 }
 
 static JSToken *
-NewToken(JSTokenStream *ts)
+NewToken(JSTokenStream *ts, ptrdiff_t adjust)
 {
     JSToken *tp;
 
     ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
     tp = &CURRENT_TOKEN(ts);
-    tp->ptr = ts->linebuf.ptr - 1;
-    tp->pos.begin.index = ts->linepos + (tp->ptr - ts->linebuf.base);
+    tp->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;
 }
@@ -763,20 +1137,21 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
     JSBool hadUnicodeEscape;
 
 #define INIT_TOKENBUF()     (ts->tokenbuf.ptr = ts->tokenbuf.base)
-#define TRIM_TOKENBUF(i)    (ts->tokenbuf.ptr = ts->tokenbuf.base + i)
-#define TOKENBUF_LENGTH()   (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 TOKENBUF_TO_ATOM()  (js_AtomizeChars(cx,                              \
-                                             TOKENBUF_BASE(),                 \
-                                             TOKENBUF_LENGTH(),               \
-                                             0))
-
-#define ADD_TO_TOKENBUF(c)                                                    \
-    JS_BEGIN_MACRO                                                            \
-        if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                     \
-            goto error;                                                       \
-    JS_END_MACRO
+#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)
@@ -784,6 +1159,7 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
 
     /* 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;
@@ -791,6 +1167,163 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
             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);
@@ -801,20 +1334,17 @@ retry:
         }
     } while (JS_ISSPACE(c));
 
-    tp = NewToken(ts);
+    tp = NewToken(ts, -1);
     if (c == EOF) {
         tt = TOK_EOF;
         goto out;
     }
 
-    if (c != '-' && c != '\n')
-        ts->flags |= TSF_DIRTYLINE;
-
     hadUnicodeEscape = JS_FALSE;
-    if (JS_ISIDENT_START(c) ||
+    if (JS_ISIDSTART(c) ||
         (c == '\\' &&
          (c = GetUnicodeEscape(ts),
-          hadUnicodeEscape = JS_ISIDENT_START(c)))) {
+          hadUnicodeEscape = JS_ISIDSTART(c)))) {
         INIT_TOKENBUF();
         for (;;) {
             ADD_TO_TOKENBUF(c);
@@ -835,11 +1365,28 @@ retry:
         if (!atom)
             goto error;
         if (!hadUnicodeEscape && ATOM_KEYWORD(atom)) {
-            struct keyword *kw = ATOM_KEYWORD(atom);
-
-            if (JSVERSION_IS_ECMA(cx->version) || kw->version <= cx->version) {
-                tp->t_op = (JSOp) kw->op;
+            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;
             }
         }
@@ -880,7 +1427,8 @@ retry:
                  * not always be so permissive, so we warn about it.
                  */
                 if (radix == 8 && c >= '8') {
-                    if (!js_ReportCompileErrorNumber(cx, ts, NULL,
+                    if (!js_ReportCompileErrorNumber(cx, ts,
+                                                     JSREPORT_TS |
                                                      JSREPORT_WARNING,
                                                      JSMSG_BAD_OCTAL,
                                                      c == '8' ? "08" : "09")) {
@@ -908,7 +1456,8 @@ retry:
                     c = GetChar(ts);
                 }
                 if (!JS7_ISDEC(c)) {
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_MISSING_EXPONENT);
                     goto error;
                 }
@@ -923,15 +1472,19 @@ retry:
         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, NULL, JSREPORT_ERROR,
+                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, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_OUT_OF_MEMORY);
                 goto error;
             }
@@ -947,7 +1500,8 @@ retry:
         while ((c = GetChar(ts)) != qc) {
             if (c == '\n' || c == EOF) {
                 UngetChar(ts, c);
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_UNTERMINATED_STRING);
                 goto error;
             }
@@ -998,7 +1552,7 @@ retry:
                             c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
                             SkipChars(ts, 2);
                         }
-                    } else if (c == '\n' && JSVERSION_IS_ECMA(cx->version)) {
+                    } else if (c == '\n' && JS_VERSION_IS_ECMA(cx)) {
                         /* ECMA follows C by removing escaped newlines. */
                         continue;
                     }
@@ -1018,25 +1572,33 @@ retry:
     }
 
     switch (c) {
-      case '\n':
-        tt = TOK_EOL;
-        break;
-
-      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 '\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 '.':
-        tt = TOK_DOT;
+#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.
@@ -1104,12 +1666,156 @@ retry:
         }
         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 <!-- comments to end of line in the middle
+         * of .js files, and after if conditions whose then statements are on
+         * the next line, and other wonders.  See at least the following bugs:
+         * https://bugzilla.mozilla.org/show_bug.cgi?id=309242
+         * https://bugzilla.mozilla.org/show_bug.cgi?id=309712
+         * https://bugzilla.mozilla.org/show_bug.cgi?id=310993
+         *
+         * So without JSOPTION_XML, we never scan an XML comment or CDATA
+         * literal.  We always scan <! as the start of an HTML comment hack
+         * to end of line, used since Netscape 2 to hide script tag content
+         * from script-unaware browsers.
+         */
+        if ((ts->flags & TSF_OPERAND) &&
+            (JS_HAS_XML_OPTION(cx) || PeekChar(ts) != '!')) {
+            /* Check for XML comment or CDATA section. */
+            if (MatchChar(ts, '!')) {
+                INIT_TOKENBUF();
+
+                /* Scan XML comment. */
+                if (MatchChar(ts, '-')) {
+                    if (!MatchChar(ts, '-'))
+                        goto bad_xml_markup;
+                    while ((c = GetChar(ts)) != '-' || !MatchChar(ts, '-')) {
+                        if (c == EOF)
+                            goto bad_xml_markup;
+                        ADD_TO_TOKENBUF(c);
+                    }
+                    tt = TOK_XMLCOMMENT;
+                    tp->t_op = JSOP_XMLCOMMENT;
+                    goto finish_xml_markup;
+                }
+
+                /* Scan CDATA section. */
+                if (MatchChar(ts, '[')) {
+                    jschar cp[6];
+                    if (PeekChars(ts, 6, cp) &&
+                        cp[0] == 'C' &&
+                        cp[1] == 'D' &&
+                        cp[2] == 'A' &&
+                        cp[3] == 'T' &&
+                        cp[4] == 'A' &&
+                        cp[5] == '[') {
+                        SkipChars(ts, 6);
+                        while ((c = GetChar(ts)) != ']' ||
+                               !PeekChars(ts, 2, cp) ||
+                               cp[0] != ']' ||
+                               cp[1] != '>') {
+                            if (c == EOF)
+                                goto bad_xml_markup;
+                            ADD_TO_TOKENBUF(c);
+                        }
+                        GetChar(ts);            /* discard ] but not > */
+                        tt = TOK_XMLCDATA;
+                        tp->t_op = JSOP_XMLCDATA;
+                        goto finish_xml_markup;
+                    }
+                    goto bad_xml_markup;
+                }
+            }
+
+            /* Check for processing instruction. */
+            if (MatchChar(ts, '?')) {
+                JSBool inTarget = JS_TRUE;
+                size_t targetLength = 0;
+                ptrdiff_t contentIndex = -1;
+
+                INIT_TOKENBUF();
+                while ((c = GetChar(ts)) != '?' || PeekChar(ts) != '>') {
+                    if (c == EOF)
+                        goto bad_xml_markup;
+                    if (inTarget) {
+                        if (JS_ISXMLSPACE(c)) {
+                            if (TOKENBUF_LENGTH() == 0)
+                                goto bad_xml_markup;
+                            inTarget = JS_FALSE;
+                        } else {
+                            if (!((TOKENBUF_LENGTH() == 0)
+                                  ? JS_ISXMLNSSTART(c)
+                                  : JS_ISXMLNS(c))) {
+                                goto bad_xml_markup;
+                            }
+                            ++targetLength;
+                        }
+                    } else {
+                        if (contentIndex < 0 && !JS_ISXMLSPACE(c))
+                            contentIndex = TOKENBUF_LENGTH();
+                    }
+                    ADD_TO_TOKENBUF(c);
+                }
+                if (contentIndex < 0) {
+                    atom = cx->runtime->atomState.emptyAtom;
+                } else {
+                    if (!TOKENBUF_OK())
+                        goto error;
+                    atom = js_AtomizeChars(cx,
+                                           &TOKENBUF_CHAR(contentIndex),
+                                           TOKENBUF_LENGTH() - contentIndex,
+                                           0);
+                    if (!atom)
+                        goto error;
+                    TRIM_TOKENBUF(targetLength);
+                }
+                tp->t_atom2 = atom;
+                tt = TOK_XMLPI;
+
+        finish_xml_markup:
+                if (!MatchChar(ts, '>'))
+                    goto bad_xml_markup;
+                atom = TOKENBUF_TO_ATOM();
+                if (!atom)
+                    goto error;
+                tp->t_atom = atom;
+                tp->pos.end.lineno = (uint16)ts->lineno;
+                goto out;
+            }
+
+            /* An XML start-of-tag character. */
+            tt = MatchChar(ts, '/') ? TOK_XMLETAGO : TOK_XMLSTAGO;
+            goto out;
+
+        bad_xml_markup:
+            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
+                                        JSMSG_BAD_XML_MARKUP);
+            goto error;
+        }
+#endif /* JS_HAS_XML_SUPPORT */
+
         /* NB: treat HTML begin-comment as comment-till-end-of-line */
         if (MatchChar(ts, '!')) {
             if (MatchChar(ts, '-')) {
-                if (MatchChar(ts, '-'))
+                if (MatchChar(ts, '-')) {
+                    ts->flags |= TSF_IN_HTML_COMMENT;
                     goto skipline;
+                }
                 UngetChar(ts, '-');
             }
             UngetChar(ts, '!');
@@ -1207,21 +1913,33 @@ retry:
             }
 
 skipline:
-            while ((c = GetChar(ts)) != EOF && c != '\n')
-                continue;
+            /* Optimize line skipping if we are not in an HTML comment. */
+            if (ts->flags & TSF_IN_HTML_COMMENT) {
+                while ((c = GetChar(ts)) != EOF && c != '\n') {
+                    if (c == '-' && MatchChar(ts, '-') && MatchChar(ts, '>'))
+                        ts->flags &= ~TSF_IN_HTML_COMMENT;
+                }
+            } else {
+                while ((c = GetChar(ts)) != EOF && c != '\n')
+                    continue;
+            }
             UngetChar(ts, c);
+            ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
             goto retry;
         }
+
         if (MatchChar(ts, '*')) {
             while ((c = GetChar(ts)) != EOF &&
                    !(c == '*' && MatchChar(ts, '/'))) {
                 /* Ignore all characters until comment close. */
             }
             if (c == EOF) {
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_UNTERMINATED_COMMENT);
                 goto error;
             }
+            ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
             goto retry;
         }
 
@@ -1229,18 +1947,28 @@ skipline:
         if (ts->flags & TSF_OPERAND) {
             JSObject *obj;
             uintN flags;
+            JSBool inCharClass = JS_FALSE;
 
             INIT_TOKENBUF();
-            while ((c = GetChar(ts)) != '/') {
+            for (;;) {
+                c = GetChar(ts);
                 if (c == '\n' || c == EOF) {
                     UngetChar(ts, c);
-                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                    js_ReportCompileErrorNumber(cx, ts,
+                                                JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_UNTERMINATED_REGEXP);
                     goto error;
                 }
                 if (c == '\\') {
                     ADD_TO_TOKENBUF(c);
                     c = GetChar(ts);
+                } else if (c == '[') {
+                    inCharClass = JS_TRUE;
+                } else if (c == ']') {
+                    inCharClass = JS_FALSE;
+                } else if (c == '/' && !inCharClass) {
+                    /* For compat with IE, allow unescaped / in char classes. */
+                    break;
                 }
                 ADD_TO_TOKENBUF(c);
             }
@@ -1257,11 +1985,16 @@ skipline:
             c = PeekChar(ts);
             if (JS7_ISLET(c)) {
                 tp->ptr = ts->linebuf.ptr - 1;
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_BAD_REGEXP_FLAG);
                 (void) GetChar(ts);
                 goto error;
             }
+            /* XXXbe fix jsregexp.c so it doesn't depend on NUL termination */
+            if (!TOKENBUF_OK())
+                goto error;
+            NUL_TERM_TOKENBUF();
             obj = js_NewRegExpObject(cx, ts,
                                      TOKENBUF_BASE(),
                                      TOKENBUF_LENGTH(),
@@ -1319,14 +2052,15 @@ skipline:
             tp->t_op = JSOP_SUB;
             tt = TOK_ASSIGN;
         } else if (MatchChar(ts, c)) {
-            if (PeekChar(ts) == '>' && !(ts->flags & TSF_DIRTYLINE))
+            if (PeekChar(ts) == '>' && !(ts->flags & TSF_DIRTYLINE)) {
+                ts->flags &= ~TSF_IN_HTML_COMMENT;
                 goto skipline;
+            }
             tt = TOK_DEC;
         } else {
             tp->t_op = JSOP_NEG;
             tt = TOK_MINUS;
         }
-        ts->flags |= TSF_DIRTYLINE;
         break;
 
 #if JS_HAS_SHARP_VARS
@@ -1346,7 +2080,8 @@ skipline:
                 break;
             n = 10 * n + JS7_UNDEC(c);
             if (n >= ATOM_INDEX_LIMIT) {
-                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+                js_ReportCompileErrorNumber(cx, ts,
+                                            JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_SHARPVAR_TOO_BIG);
                 goto error;
             }
@@ -1356,7 +2091,8 @@ skipline:
             (c == '=' || c == '#')) {
             char buf[20];
             JS_snprintf(buf, sizeof buf, "#%u%c", n, c);
-            if (!js_ReportCompileErrorNumber(cx, ts, NULL,
+            if (!js_ReportCompileErrorNumber(cx, ts,
+                                             JSREPORT_TS |
                                              JSREPORT_WARNING |
                                              JSREPORT_STRICT,
                                              JSMSG_DEPRECATED_USAGE,
@@ -1372,20 +2108,28 @@ skipline:
             goto badchar;
         break;
       }
+#endif /* JS_HAS_SHARP_VARS */
 
+#if JS_HAS_SHARP_VARS || JS_HAS_XML_SUPPORT
       badchar:
-#endif /* JS_HAS_SHARP_VARS */
+#endif
 
       default:
-        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
+        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_ILLEGAL_CHARACTER);
         goto error;
     }
 
 out:
+    JS_ASSERT(tt != TOK_EOL);
+    ts->flags |= TSF_DIRTYLINE;
+
+eol_out:
+    if (!STRING_BUFFER_OK(&ts->tokenbuf))
+        tt = TOK_ERROR;
     JS_ASSERT(tt < TOK_LIMIT);
     tp->pos.end.index = ts->linepos +
-                        (ts->linebuf.ptr - ts->linebuf.base) -
+                        PTRDIFF(ts->linebuf.ptr, ts->linebuf.base, jschar) -
                         ts->ungetpos;
     tp->type = tt;
     return tt;
@@ -1396,12 +2140,14 @@ error:
     goto out;
 
 #undef INIT_TOKENBUF
-#undef TRIM_TOKENBUF
 #undef TOKENBUF_LENGTH
-#undef TOKENBUF_BASE
-#undef TOKENBUF_CHAR
+#undef TOKENBUF_OK
 #undef TOKENBUF_TO_ATOM
 #undef ADD_TO_TOKENBUF
+#undef TOKENBUF_BASE
+#undef TOKENBUF_CHAR
+#undef TRIM_TOKENBUF
+#undef NUL_TERM_TOKENBUF
 }
 
 void
index 121b35df31c32d8b4bce59546e1cd4767783f710..ee39bbc0af85f987ae2a196c25a1db736f99e739 100644 (file)
@@ -107,6 +107,24 @@ typedef enum JSTokenType {
     TOK_THROW = 58,                     /* throw keyword */
     TOK_INSTANCEOF = 59,                /* instanceof keyword */
     TOK_DEBUGGER = 60,                  /* debugger keyword */
+    TOK_XMLSTAGO = 61,                  /* XML start tag open (<) */
+    TOK_XMLETAGO = 62,                  /* XML end tag open (</) */
+    TOK_XMLPTAGC = 63,                  /* XML point tag close (/>) */
+    TOK_XMLTAGC = 64,                   /* XML start or end tag close (>) */
+    TOK_XMLNAME = 65,                   /* XML start-tag non-final fragment */
+    TOK_XMLATTR = 66,                   /* XML quoted attribute value */
+    TOK_XMLSPACE = 67,                  /* XML whitespace */
+    TOK_XMLTEXT = 68,                   /* XML text */
+    TOK_XMLCOMMENT = 69,                /* XML comment */
+    TOK_XMLCDATA = 70,                  /* XML CDATA section */
+    TOK_XMLPI = 71,                     /* XML processing instruction */
+    TOK_AT = 72,                        /* XML attribute op (@) */
+    TOK_DBLCOLON = 73,                  /* namespace qualified name op (::) */
+    TOK_ANYNAME = 74,                   /* XML AnyName singleton (*) */
+    TOK_DBLDOT = 75,                    /* XML descendant op (..) */
+    TOK_FILTER = 76,                    /* XML filtering predicate op (.()) */
+    TOK_XMLELEM = 77,                   /* XML element node type (no token) */
+    TOK_XMLLIST = 78,                   /* XML list node type (no token) */
     TOK_RESERVED,                       /* reserved keywords */
     TOK_LIMIT                           /* domain size */
 } JSTokenType;
@@ -114,6 +132,40 @@ typedef enum JSTokenType {
 #define IS_PRIMARY_TOKEN(tt) \
     ((uintN)((tt) - TOK_NAME) <= (uintN)(TOK_PRIMARY - TOK_NAME))
 
+#define TOKEN_TYPE_IS_XML(tt) \
+    (tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME)
+
+struct JSStringBuffer {
+    jschar      *base;
+    jschar      *limit;         /* length limit for quick bounds check */
+    jschar      *ptr;           /* slot for next non-NUL char to store */
+    void        *data;
+    JSBool      (*grow)(JSStringBuffer *sb, size_t newlength);
+    void        (*free)(JSStringBuffer *sb);
+};
+
+#define STRING_BUFFER_ERROR_BASE        ((jschar *) 1)
+#define STRING_BUFFER_OK(sb)            ((sb)->base != STRING_BUFFER_ERROR_BASE)
+#define STRING_BUFFER_OFFSET(sb)        ((sb)->ptr -(sb)->base)
+
+extern void
+js_InitStringBuffer(JSStringBuffer *sb);
+
+extern void
+js_FinishStringBuffer(JSStringBuffer *sb);
+
+extern void
+js_AppendChar(JSStringBuffer *sb, jschar c);
+
+extern void
+js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count);
+
+extern void
+js_AppendCString(JSStringBuffer *sb, const char *asciiz);
+
+extern void
+js_AppendJSString(JSStringBuffer *sb, JSString *str);
+
 struct JSTokenPtr {
     uint16              index;          /* index of char in physical line */
     uint16              lineno;         /* physical line number */
@@ -129,16 +181,21 @@ struct JSToken {
     JSTokenPos          pos;            /* token position in file */
     jschar              *ptr;           /* beginning of token in line buffer */
     union {
-        struct {
+        struct {                        /* non-numeric literal */
             JSOp        op;             /* operator, for minimal parser */
             JSAtom      *atom;          /* atom table entry */
         } s;
+        struct {                        /* atom pair, for XML PIs */
+            JSAtom      *atom2;         /* auxiliary atom table entry */
+            JSAtom      *atom;          /* main atom table entry */
+        } p;
         jsdouble        dval;           /* floating point number */
     } u;
 };
 
 #define t_op            u.s.op
 #define t_atom          u.s.atom
+#define t_atom2         u.p.atom2
 #define t_dval          u.dval
 
 typedef struct JSTokenBuf {
@@ -164,7 +221,7 @@ struct JSTokenStream {
     ptrdiff_t           linepos;        /* linebuf offset in physical line */
     JSTokenBuf          linebuf;        /* line buffer for diagnostics */
     JSTokenBuf          userbuf;        /* user input buffer if !file */
-    JSTokenBuf          tokenbuf;       /* current token string buffer */
+    JSStringBuffer      tokenbuf;       /* current token string buffer */
     const char          *filename;      /* input filename or null */
     FILE                *file;          /* stdio stream if reading from file */
     JSPrincipals        *principals;    /* principals associated with source */
@@ -187,6 +244,33 @@ struct JSTokenStream {
 #define TSF_CRFLAG      0x40            /* linebuf would have ended with \r */
 #define TSF_DIRTYLINE   0x80            /* non-whitespace since start of line */
 #define TSF_OWNFILENAME 0x100           /* ts->filename is malloc'd */
+#define TSF_XMLTAGMODE  0x200           /* scanning within an XML tag in E4X */
+#define TSF_XMLTEXTMODE 0x400           /* scanning XMLText terminal from E4X */
+#define TSF_XMLONLYMODE 0x800           /* don't scan {expr} within text/tag */
+
+/* Flag indicating unexpected end of input, i.e. TOK_EOF not at top-level. */
+#define TSF_UNEXPECTED_EOF 0x1000
+
+/*
+ * To handle the hard case of contiguous HTML comments, we want to clear the
+ * TSF_DIRTYINPUT flag at the end of each such comment.  But we'd rather not
+ * scan for --> within every //-style comment unless we have to.  So we set
+ * TSF_IN_HTML_COMMENT when a <!-- is scanned as an HTML begin-comment, and
+ * clear it (and TSF_DIRTYINPUT) when we scan --> 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:
+ *
+ *    <script>
+ *      <!-- comment hiding hack #1
+ *      code goes here
+ *      // --> oops, markup for script-unaware browsers goes here!
+ *    </script>
+ *
+ * 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
@@ -213,6 +297,9 @@ 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.
  */
@@ -231,9 +318,18 @@ js_MapKeywords(void (*mapfun)(const char *));
  * Return true for a warning, false for an error.
  */
 extern JSBool
-js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts,
-                            JSCodeGenerator *cg, uintN flags,
-                            const uintN errorNumber, ...);
+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.
index e3603b18f699e1e67ec523eaffe0ad1794770468..4f951238724ef76db9878fa8f1fdba1328f0a77d 100644 (file)
@@ -98,7 +98,7 @@ InitMinimalScope(JSScope *scope)
 }
 
 static JSBool
-CreateScopeTable(JSScope *scope)
+CreateScopeTable(JSContext *cx, JSScope *scope, JSBool report)
 {
     int sizeLog2;
     JSScopeProperty *sprop, **spp;
@@ -120,8 +120,14 @@ CreateScopeTable(JSScope *scope)
 
     scope->table = (JSScopeProperty **)
         calloc(JS_BIT(sizeLog2), sizeof(JSScopeProperty *));
-    if (!scope->table)
+    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) {
@@ -144,6 +150,7 @@ js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
     js_InitObjectMap(&scope->map, nrefs, ops, clasp);
     scope->object = obj;
     scope->flags = 0;
+    scope->dswIndex = 0;
     InitMinimalScope(scope);
 
 #ifdef JS_THREADSAFE
@@ -347,6 +354,9 @@ ChangeScope(JSContext *cx, JSScope *scope, int change)
     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);
@@ -528,7 +538,7 @@ DestroyPropTreeKidsChunk(JSRuntime *rt, PropTreeKidsChunk *chunk)
 /* NB: Called with the runtime lock held. */
 static JSBool
 InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent,
-                        JSScopeProperty *child)
+                        JSScopeProperty *child, PropTreeKidsChunk *sweptChunk)
 {
     JSPropertyTreeEntry *entry;
     JSScopeProperty **childp, *kids, *sprop;
@@ -594,9 +604,13 @@ InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent,
                     chunkp = &chunk->next;
                 } while ((chunk = *chunkp) != NULL);
 
-                chunk = NewPropTreeKidsChunk(rt);
-                if (!chunk)
-                    return JS_FALSE;
+                if (sweptChunk) {
+                    chunk = sweptChunk;
+                } else {
+                    chunk = NewPropTreeKidsChunk(rt);
+                    if (!chunk)
+                        return JS_FALSE;
+                }
                 *chunkp = chunk;
                 childp = &chunk->kids[0];
             } else {
@@ -776,7 +790,7 @@ GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
     if (!parent) {
         entry->child = sprop;
     } else {
-        if (!InsertPropertyTreeChild(rt, parent, sprop))
+        if (!InsertPropertyTreeChild(rt, parent, sprop, NULL))
             goto out_of_memory;
     }
 
@@ -967,10 +981,8 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
                  * delete code is simple-minded that way!
                  */
                 if (!scope->table) {
-                    if (!CreateScopeTable(scope)) {
-                        JS_ReportOutOfMemory(cx);
+                    if (!CreateScopeTable(cx, scope, JS_TRUE))
                         return NULL;
-                    }
                     spp = js_SearchScope(scope, id, JS_TRUE);
                     sprop = overwriting = SPROP_FETCH(spp);
                 }
@@ -1166,7 +1178,7 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
          * entry count just reached the threshold.
          */
         if (!scope->table && scope->entryCount >= SCOPE_HASH_THRESHOLD)
-            (void) CreateScopeTable(scope);
+            (void) CreateScopeTable(cx, scope, JS_FALSE);
     }
 
     METER(adds);
@@ -1308,10 +1320,8 @@ js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id)
 
     /* Convert from a list to a hash so we can handle "middle deletes". */
     if (!scope->table && sprop != scope->lastProp) {
-        if (!CreateScopeTable(scope)) {
-            JS_ReportOutOfMemory(cx);
+        if (!CreateScopeTable(cx, scope, JS_TRUE))
             return JS_FALSE;
-        }
         spp = js_SearchScope(scope, id, JS_FALSE);
         stored = *spp;
         sprop = SPROP_CLEAR_COLLISION(stored);
@@ -1445,10 +1455,12 @@ DumpSubtree(JSScopeProperty *sprop, int level, FILE *fp)
 
     fprintf(fp, "%*sid %s g/s %p/%p slot %lu attrs %x flags %x shortid %d\n",
             level, "",
-            JSVAL_IS_INT(sprop->id)
-            ? (JS_snprintf(buf, sizeof buf, "%ld", JSVAL_TO_INT(sprop->id)),
+            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)
-            : JS_GetStringBytes(ATOM_TO_STRING((JSAtom *) sprop->id)),
             (void *) sprop->getter, (void *) sprop->setter,
             (unsigned long) sprop->slot, sprop->attrs, sprop->flags,
             sprop->shortid);
@@ -1546,27 +1558,78 @@ js_SweepScopeProperties(JSRuntime *rt)
             /* 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. */
+            /*
+             * 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);
-                            InsertPropertyTreeChild(rt, parent, kid);
+
+                            /*
+                             * 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);
                         }
-                        nextChunk = chunk->next;
-                        DestroyPropTreeKidsChunk(rt, chunk);
                     } while ((chunk = nextChunk) != NULL);
                 } else {
                     kid = kids;
-                    InsertPropertyTreeChild(rt, parent, kid);
+                    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;
+                    }
                 }
             }
 
index 8ac7ef073bca5db696cd2f9dd9e67f7af6fee765..0f8a837c0f8a47c994e163c7f9d863a06cecdf04 100644 (file)
@@ -99,7 +99,7 @@
  * 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
 struct JSScope {
     JSObjectMap     map;                /* base class state */
     JSObject        *object;            /* object that owns this scope */
-    uint16          flags;              /* flags, see below */
-    int16           hashShift;          /* multiplicative hash shift */
+    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 */
@@ -290,6 +291,8 @@ struct JSScopeProperty {
 #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
@@ -345,10 +348,12 @@ js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
 extern void
 js_DestroyScope(JSContext *cx, JSScope *scope);
 
-#define ID_TO_VALUE(id) (((id) & JSVAL_INT) ? id : ATOM_KEY((JSAtom *)(id)))
-#define HASH_ID(id)     (((id) & JSVAL_INT)                                   \
-                         ? (jsatomid) JSVAL_TO_INT(id)                        \
-                         : ((JSAtom *)id)->number)
+#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);
index 7e5aefc306cca12aa6a0d3a9a236cb3588bbc606..6fc92de930109afc9598501a0f9cfcf6a87fe23e 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
@@ -63,6 +64,9 @@
 
 #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,
@@ -157,8 +161,8 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                jsval *rval)
 {
     JSScript *oldscript, *script;
-    JSString *str;
     JSStackFrame *fp, *caller;
+    JSString *str;
     JSObject *scopeobj;
     const char *file;
     uintN line;
@@ -172,10 +176,23 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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;
@@ -201,6 +218,11 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         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
@@ -209,6 +231,7 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
      * 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),
@@ -217,7 +240,6 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         return JS_FALSE;
 
     /* Swap script for obj's old script, if any. */
-    oldscript = (JSScript *) JS_GetPrivate(cx, obj);
     if (!JS_SetPrivate(cx, obj, script)) {
         js_DestroyScript(cx, script);
         return JS_FALSE;
@@ -238,6 +260,7 @@ 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;
@@ -297,6 +320,15 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         }
     }
 
+    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);
 }
 
@@ -704,6 +736,7 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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);
@@ -839,6 +872,12 @@ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         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);
 }
@@ -899,7 +938,8 @@ typedef struct ScriptFilenameEntry {
     JSHashEntry         *next;          /* hash chain linkage */
     JSHashNumber        keyHash;        /* key hash function result */
     const void          *key;           /* ptr to filename, below */
-    JSPackedBool        mark;           /* mark flag, for GC */
+    uint32              flags;          /* user-defined filename prefix flags */
+    JSPackedBool        mark;           /* GC mark flag */
     char                filename[3];    /* two or more bytes, NUL-terminated */
 } ScriptFilenameEntry;
 
@@ -919,45 +959,42 @@ js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag)
     free(he);
 }
 
-static JSHashAllocOps table_alloc_ops = {
+static JSHashAllocOps sftbl_alloc_ops = {
     js_alloc_table_space,   js_free_table_space,
     js_alloc_sftbl_entry,   js_free_sftbl_entry
 };
 
 JSBool
-js_InitRuntimeScriptState(JSContext *cx)
+js_InitRuntimeScriptState(JSRuntime *rt)
 {
-    JSRuntime *rt = cx->runtime;
-
 #ifdef JS_THREADSAFE
-    /* Must come through here once in primordial thread to init safely! */
-    if (!rt->scriptFilenameTableLock) {
-        rt->scriptFilenameTableLock = JS_NEW_LOCK();
-        if (!rt->scriptFilenameTableLock)
-            return JS_FALSE;
-    }
+    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_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
-        if (!rt->scriptFilenameTable) {
-            rt->scriptFilenameTable =
-                JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL,
-                                &table_alloc_ops, NULL);
-        }
-        JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
-        if (!rt->scriptFilenameTable) {
-            js_FinishRuntimeScriptState(cx);    /* free lock if threadsafe */
-            return JS_FALSE;
-        }
+        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(JSContext *cx)
+js_FinishRuntimeScriptState(JSRuntime *rt)
 {
-    JSRuntime *rt = cx->runtime;
-
     if (rt->scriptFilenameTable) {
         JS_HashTableDestroy(rt->scriptFilenameTable);
         rt->scriptFilenameTable = NULL;
@@ -970,20 +1007,34 @@ js_FinishRuntimeScriptState(JSContext *cx)
 #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
 
-const char *
-js_SaveScriptFilename(JSContext *cx, const char *filename)
+static ScriptFilenameEntry *
+SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags)
 {
-    JSRuntime *rt = cx->runtime;
     JSHashTable *table;
     JSHashNumber hash;
     JSHashEntry **hep;
     ScriptFilenameEntry *sfe;
+    size_t length;
+    JSCList *head, *link;
+    ScriptFilenamePrefix *sfp;
 
-    JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
     table = rt->scriptFilenameTable;
     hash = JS_HashString(filename);
     hep = JS_HashTableRawLookup(table, hash, filename);
@@ -992,40 +1043,174 @@ js_SaveScriptFilename(JSContext *cx, const char *filename)
     if (sfe)
         sftbl_savings += strlen(sfe->filename);
 #endif
+
     if (!sfe) {
         sfe = (ScriptFilenameEntry *)
               JS_HashTableRawAdd(table, hep, hash, filename, NULL);
-        if (sfe) {
-            sfe->key = strcpy(sfe->filename, filename);
-            JS_ASSERT(!sfe->mark);
+        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;
     }
-    JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
+
+    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;
 
-    /*
-     * Back up from filename by its offset within its hash table entry.
-     * The sfe->key member, redundant given sfe->filename but required by
-     * the old jshash.c code, here gives us a useful sanity check.  This
-     * assertion will very likely botch if someone tries to mark a string
-     * that wasn't allocated as an sfe->filename.
-     */
-    sfe = (ScriptFilenameEntry *)
-          (filename - offsetof(ScriptFilenameEntry, filename));
-    JS_ASSERT(sfe->key == sfe->filename);
+    sfe = 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)
 {
@@ -1043,7 +1228,7 @@ js_SweepScriptFilenames(JSRuntime *rt)
     JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
                                  js_script_filename_sweeper,
                                  rt);
-#ifdef DEBUG_brendan
+#ifdef DEBUG_notme
     printf("script filename table savings so far: %u\n", sftbl_savings);
 #endif
 }
@@ -1142,8 +1327,8 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
     }
 }
 
-void
-js_DestroyScript(JSContext *cx, JSScript *script)
+JS_FRIEND_API(void)
+js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
 {
     JSRuntime *rt;
     JSDestroyScriptHook hook;
@@ -1152,6 +1337,12 @@ js_DestroyScript(JSContext *cx, JSScript *script)
     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);
@@ -1240,19 +1431,31 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
     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;
-    uintN lineno;
+    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)
-            break;
+        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) {
@@ -1261,10 +1464,13 @@ js_LineNumberToPC(JSScript *script, uintN target)
             lineno++;
         }
     }
+    if (best >= 0)
+        offset = best;
+out:
     return script->code + offset;
 }
 
-uintN
+JS_FRIEND_API(uintN)
 js_GetScriptLineExtent(JSScript *script)
 {
     uintN lineno;
index 6284917afe95b35b88d0ff13afeb01223319043a..77f59ed751440e8dcffd6f2f8de8334443e3c00c 100644 (file)
@@ -50,8 +50,8 @@ JS_BEGIN_EXTERN_C
 /*
  * Exception handling runtime information.
  *
- * All fields except length are code offsets, relative to the beginning of
- * the script.  If script->trynotes is not null, it points to a vector of
+ * 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 {
@@ -102,18 +102,45 @@ 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(JSContext *cx);
+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_FinishRuntimeScriptState(JSContext *cx);
+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);
 
@@ -143,6 +170,9 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *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);
 
@@ -159,7 +189,7 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
 extern jsbytecode *
 js_LineNumberToPC(JSScript *script, uintN lineno);
 
-extern uintN
+extern JS_FRIEND_API(uintN)
 js_GetScriptLineExtent(JSScript *script);
 
 /*
index 0d87b0c0c7cb8fb92838d590f4f6736f7d1942a7..addaa88ff6f08fb98fe05b0ae6b874564dd06cf5 100644 (file)
@@ -74,7 +74,7 @@ typedef long ptrdiff_t;
 #else /*WIN16*/
 
 #define PTRDIFF(p1, p2, type)                                 \
-       ((p1) - (p2))
+        ((p1) - (p2))
 
 #endif
 
index e143ab8dfcac4d49f458191129072c18db9a23dc..5e0bafd3ba626251b130058f88f1f40682c3b6ac 100644 (file)
@@ -1,4 +1,5 @@
 /* -*- 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
@@ -167,7 +168,7 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
         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)
@@ -266,9 +267,6 @@ static JSBool
 str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                         jsval *rval);
 
-static int
-OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char);
-
 static uint32
 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
 
@@ -360,6 +358,20 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
         } 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));
@@ -512,9 +524,16 @@ str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
     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));
@@ -529,15 +548,21 @@ 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_FALSE;
+        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_JSVAL(i),
+        if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(i),
                                  STRING_TO_JSVAL(str1), NULL, NULL,
                                  STRING_ELEMENT_ATTRS, NULL)) {
             return JS_FALSE;
@@ -547,36 +572,40 @@ str_enumerate(JSContext *cx, JSObject *obj)
 }
 
 static JSBool
-str_resolve(JSContext *cx, JSObject *obj, jsval id)
+str_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
+            JSObject **objp)
 {
     JSString *str, *str1;
     jsint slot;
 
-    if (!JSVAL_IS_INT(id))
+    if (!JSVAL_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING))
         return JS_TRUE;
 
     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
     if (!str)
-        return JS_FALSE;
+        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_JSVAL(slot),
+        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;
 }
 
-static JSClass string_class = {
+JSClass js_StringClass = {
     js_String_str,
-    JSCLASS_HAS_PRIVATE,
-    JS_PropertyStub,  JS_PropertyStub,  str_getProperty,  JS_PropertyStub,
-    str_enumerate,    str_resolve,      JS_ConvertStub,   JS_FinalizeStub,
+    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
 };
 
@@ -594,6 +623,8 @@ str_quote(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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;
@@ -610,7 +641,7 @@ str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     char buf[16];
     jschar *s, *t;
 
-    if (!JS_InstanceOf(cx, obj, &string_class, argv))
+    if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
         return JS_FALSE;
     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
     if (!JSVAL_IS_STRING(v))
@@ -618,7 +649,7 @@ str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
     if (!str)
         return JS_FALSE;
-    j = JS_snprintf(buf, sizeof buf, "(new %s(", string_class.name);
+    j = JS_snprintf(buf, sizeof buf, "(new %s(", js_StringClass.name);
     s = JSSTRING_CHARS(str);
     k = JSSTRING_LENGTH(str);
     n = j + k + 2;
@@ -648,7 +679,7 @@ str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     jsval v;
 
-    if (!JS_InstanceOf(cx, obj, &string_class, argv))
+    if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
         return JS_FALSE;
     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
     if (!JSVAL_IS_STRING(v))
@@ -660,7 +691,7 @@ str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 static JSBool
 str_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    if (!JS_InstanceOf(cx, obj, &string_class, argv))
+    if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
         return JS_FALSE;
     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
     return JS_TRUE;
@@ -703,7 +734,7 @@ str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
             else if (end > length)
                 end = length;
             if (end < begin) {
-                if (cx->version != JSVERSION_1_2) {
+                if (!JS_VERSION_IS_1_2(cx)) {
                     /* XXX emulate old JDK1.0 java.lang.String.substring. */
                     jsdouble tmp = begin;
                     begin = end;
@@ -734,6 +765,8 @@ str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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)
@@ -765,6 +798,7 @@ str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         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);
@@ -781,6 +815,8 @@ str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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)
@@ -812,6 +848,7 @@ str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         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);
@@ -834,8 +871,10 @@ str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         thatStr = js_ValueToString(cx, argv[0]);
         if (!thatStr)
             return JS_FALSE;
-        if (cx->localeCallbacks && cx->localeCallbacks->localeCompare)
+        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;
@@ -1033,8 +1072,8 @@ str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
             d = js_DoubleToInteger(d);
             if (d < 0)
                 i = 0;
-            else if (d > textlen - patlen)
-                i = textlen - patlen;
+            else if (d > textlen)
+                i = textlen;
             else
                 i = (jsint)d;
         }
@@ -1126,7 +1165,9 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
             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;
@@ -1142,23 +1183,23 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         if (reobj) {
             /* Set the lastIndex property's reserved slot to 0. */
             ok = js_SetLastIndex(cx, reobj, 0);
-            if (!ok)
-                return JS_FALSE;
         } else {
             ok = JS_TRUE;
         }
-        length = JSSTRING_LENGTH(str);
-        for (count = 0; index <= length; count++) {
-            ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
-            if (!ok || *rval != JSVAL_TRUE)
-                break;
-            ok = glob(cx, count, data);
-            if (!ok)
-                break;
-            if (cx->regExpStatics.lastMatch.length == 0) {
-                if (index == length)
+        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;
-                index++;
+                ok = glob(cx, count, data);
+                if (!ok)
+                    break;
+                if (cx->regExpStatics.lastMatch.length == 0) {
+                    if (index == length)
+                        break;
+                    index++;
+                }
             }
         }
     } else {
@@ -1171,25 +1212,35 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
              * vs. non-null return value, optimize away the array object that
              * would normally be returned in *rval.
              */
-            JS_ASSERT(*cx->fp->down->pc == JSOP_CALL ||
-                      *cx->fp->down->pc == JSOP_NEW);
-            JS_ASSERT(js_CodeSpec[*cx->fp->down->pc].length == 3);
-            switch (cx->fp->down->pc[3]) {
-              case JSOP_POP:
-              case JSOP_IFEQ:
-              case JSOP_IFNE:
-              case JSOP_IFEQX:
-              case JSOP_IFNEX:
-                test = JS_TRUE;
-                break;
-              default:
-                test = JS_FALSE;
-                break;
+            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;
@@ -1198,6 +1249,7 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         data->regexp = NULL;
         js_DestroyRegExp(cx, re);
     }
+
     return ok;
 }
 
@@ -1228,7 +1280,7 @@ match_glob(JSContext *cx, jsint count, GlobData *data)
     if (!matchstr)
         return JS_FALSE;
     v = STRING_TO_JSVAL(matchstr);
-    return js_SetProperty(cx, arrayobj, INT_TO_JSVAL(count), &v);
+    return js_SetProperty(cx, arrayobj, INT_TO_JSID(count), &v);
 }
 
 static JSBool
@@ -1271,8 +1323,10 @@ typedef struct ReplaceData {
 } ReplaceData;
 
 static JSSubString *
-interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
+interpret_dollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData *rdata,
+                 size_t *skip)
 {
+    JSVersion version;
     JSRegExpStatics *res;
     jschar dc, *cp;
     uintN num, tmp;
@@ -1284,23 +1338,28 @@ interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
      * Allow a real backslash (literal "\\" before "$1") to escape "$1", e.g.
      * Do this only for versions strictly less than ECMAv3.
      */
-    if (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
+    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 (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
+        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 ((dc = *++cp) != 0 && JS7_ISDEC(dc)) {
+            while (++cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
                 tmp = 10 * num + JS7_UNDEC(dc);
                 if (tmp < num)
                     break;
@@ -1310,9 +1369,9 @@ interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
             num = JS7_UNDEC(dc);
             if (num > res->parenCount)
                 return NULL;
+
             cp = dp + 2;
-            dc = *cp;
-            if ((dc != 0) && JS7_ISDEC(dc)) {
+            if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
                 tmp = 10 * num + JS7_UNDEC(dc);
                 if (tmp <= res->parenCount) {
                     cp++;
@@ -1339,7 +1398,7 @@ interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
       case '+':
         return &res->lastParen;
       case '`':
-        if (cx->version == JSVERSION_1_2) {
+        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,
@@ -1378,11 +1437,13 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
         JSBool ok;
 
         /*
-         * Save the rightContext from the current regexp, since it
-         * gets stuck at the end of the replacement string and may
-         * be clobbered by a RegExp usage in the lambda function.
+         * 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.
          */
-        JSSubString saveRightContext = cx->regExpStatics.rightContext;
+        JSRegExpStatics save = cx->regExpStatics;
+        JSBool freeMoreParens = JS_FALSE;
 
         /*
          * In the lambda case, not only do we find the replacement string's
@@ -1425,6 +1486,14 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
         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. */
@@ -1460,7 +1529,9 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
 
       lambda_out:
         js_FreeStack(cx, mark);
-        cx->regExpStatics.rightContext = saveRightContext;
+        if (freeMoreParens)
+            JS_free(cx, cx->regExpStatics.moreParens);
+        cx->regExpStatics = save;
         return ok;
     }
 #endif /* JS_HAS_REPLACE_LAMBDA */
@@ -1469,7 +1540,7 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
     replen = JSSTRING_LENGTH(repstr);
     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
          dp = js_strchr_limit(dp, '$', ep)) {
-        sub = interpret_dollar(cx, dp, rdata, &skip);
+        sub = interpret_dollar(cx, dp, ep, rdata, &skip);
         if (sub) {
             replen += sub->length - skip;
             dp += skip;
@@ -1497,7 +1568,7 @@ do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
         js_strncpy(chars, cp, len);
         chars += len;
         cp = dp;
-        sub = interpret_dollar(cx, dp, rdata, &skip);
+        sub = interpret_dollar(cx, dp, ep, rdata, &skip);
         if (sub) {
             len = sub->length;
             js_strncpy(chars, sub->chars, len);
@@ -1556,6 +1627,7 @@ 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;
@@ -1579,7 +1651,8 @@ str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
      * special meanings) UNLESS the first arg is a RegExp object.
      */
     rdata.base.flags = MODE_REPLACE | KEEP_REGEXP;
-    if (cx->version == JSVERSION_DEFAULT || cx->version > JSVERSION_1_4)
+    version = cx->version & JSVERSION_MASK;
+    if (version == JSVERSION_DEFAULT || version > JSVERSION_1_4)
         rdata.base.flags |= FORCE_FLAT;
     rdata.base.optarg = 2;
 
@@ -1694,7 +1767,7 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
      */
     chars = JSSTRING_CHARS(str);
     length = JSSTRING_LENGTH(str);
-    if (cx->version == JSVERSION_1_2 &&
+    if (JS_VERSION_IS_1_2(cx) &&
         !re && *sep->chars == ' ' && sep->chars[1] == 0) {
 
         /* Skip leading whitespace if at front of str. */
@@ -1757,7 +1830,7 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
                  * sep->length to our return value.
                  */
                 if ((size_t)i == length) {
-                    if (cx->version == JSVERSION_1_2) {
+                    if (JS_VERSION_IS_1_2(cx)) {
                         sep->length = 1;
                         return i;
                     }
@@ -1766,6 +1839,14 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
                 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;
@@ -1777,7 +1858,7 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
      * string into a non-empty array (an array of length 1 that contains the
      * empty string).
      */
-    if (!JSVERSION_IS_ECMA(cx->version) && length == 0)
+    if (!JS_VERSION_IS_ECMA(cx) && length == 0)
         return -1;
 
     /*
@@ -1790,7 +1871,7 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
      * to include an additional null string at the end of the substring list.
      */
     if (sep->length == 0) {
-        if (cx->version == JSVERSION_1_2) {
+        if (JS_VERSION_IS_1_2(cx)) {
             if ((size_t)i == length) {
                 sep->length = 1;
                 return i;
@@ -1922,7 +2003,7 @@ str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
             }
 #endif
             i = j + sep->length;
-            if (!JSVERSION_IS_ECMA(cx->version)) {
+            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.
@@ -1947,6 +2028,7 @@ str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     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))
@@ -2072,7 +2154,7 @@ str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
  */
 static JSBool
 tagify(JSContext *cx, JSObject *obj, jsval *argv,
-       const char *begin, const jschar *param, const char *end,
+       const char *begin, JSString *param, const char *end,
        jsval *rval)
 {
     JSString *str;
@@ -2092,12 +2174,17 @@ tagify(JSContext *cx, JSObject *obj, jsval *argv,
     taglen = 1 + beglen + 1;                            /* '<begin' + '>' */
     parlen = 0; /* Avoid warning. */
     if (param) {
-        parlen = js_strlen(param);
+        parlen = JSSTRING_LENGTH(param);
         taglen += 2 + parlen + 1;                       /* '="param"' */
     }
     endlen = strlen(end);
     taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1;    /* 'str</end>' */
 
+    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;
@@ -2109,7 +2196,7 @@ tagify(JSContext *cx, JSObject *obj, jsval *argv,
     if (param) {
         tagbuf[j++] = '=';
         tagbuf[j++] = '"';
-        js_strncpy(&tagbuf[j], param, parlen);
+        js_strncpy(&tagbuf[j], JSSTRING_CHARS(param), parlen);
         j += parlen;
         tagbuf[j++] = '"';
     }
@@ -2144,7 +2231,7 @@ tagify_value(JSContext *cx, JSObject *obj, jsval *argv,
     if (!param)
         return JS_FALSE;
     argv[0] = STRING_TO_JSVAL(param);
-    return tagify(cx, obj, argv, begin, JSSTRING_CHARS(param), end, rval);
+    return tagify(cx, obj, argv, begin, param, end, rval);
 }
 
 static JSBool
@@ -2229,39 +2316,39 @@ str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
 static JSFunctionSpec string_methods[] = {
 #if JS_HAS_TOSOURCE
-    {"quote",               str_quote,              0,0,0},
+    {"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,0,0},
-    {"toLowerCase",         str_toLowerCase,        0,0,0},
-    {"toUpperCase",         str_toUpperCase,        0,0,0},
-    {"charAt",              str_charAt,             1,0,0},
-    {"charCodeAt",          str_charCodeAt,         1,0,0},
-    {"indexOf",             str_indexOf,            1,0,0},
-    {"lastIndexOf",         str_lastIndexOf,        1,0,0},
-    {"toLocaleLowerCase",   str_toLocaleLowerCase,  0,0,0},
-    {"toLocaleUpperCase",   str_toLocaleUpperCase,  0,0,0},
-    {"localeCompare",       str_localeCompare,      1,0,0},
+    {"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,0,2},
-    {"search",              str_search,             1,0,0},
-    {"replace",             str_replace,            2,0,0},
-    {"split",               str_split,              2,0,0},
+    {"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,0,0},
+    {"substr",              str_substr,             2,JSFUN_GENERIC_NATIVE,0},
 #endif
 
     /* Python-esque sequence methods. */
 #if JS_HAS_SEQUENCE_OPS
-    {"concat",              str_concat,             0,0,0},
-    {"slice",               str_slice,              0,0,0},
+    {"concat",              str_concat,             0,JSFUN_GENERIC_NATIVE,0},
+    {"slice",               str_slice,              0,JSFUN_GENERIC_NATIVE,0},
 #endif
 
     /* HTML string methods. */
@@ -2293,6 +2380,7 @@ String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
         str = js_ValueToString(cx, argv[0]);
         if (!str)
             return JS_FALSE;
+        argv[0] = STRING_TO_JSVAL(str);
     } else {
         str = cx->runtime->emptyString;
     }
@@ -2380,6 +2468,7 @@ js_InitRuntimeStringState(JSContext *cx)
 {
     JSRuntime *rt;
     JSString *empty;
+    JSAtom *atom;
 
     rt = cx->runtime;
     JS_ASSERT(!rt->emptyString);
@@ -2390,10 +2479,12 @@ js_InitRuntimeStringState(JSContext *cx)
         return JS_FALSE;
 
     /* Atomize it for scripts that use '' + x to convert x to string. */
-    if (!js_AtomizeString(cx, empty, ATOM_PINNED))
+    atom = js_AtomizeString(cx, empty, ATOM_PINNED);
+    if (!atom)
         return JS_FALSE;
 
     rt->emptyString = empty;
+    rt->atomState.emptyAtom = atom;
     return JS_TRUE;
 }
 
@@ -2415,7 +2506,7 @@ js_InitStringClass(JSContext *cx, JSObject *obj)
     if (!JS_DefineFunctions(cx, obj, string_functions))
         return NULL;
 
-    proto = JS_InitClass(cx, obj, NULL, &string_class, String, 1,
+    proto = JS_InitClass(cx, obj, NULL, &js_StringClass, String, 1,
                          string_props, string_methods,
                          NULL, string_static_methods);
     if (!proto)
@@ -2435,7 +2526,7 @@ js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
         return NULL;
     }
 
-    str = (JSString *) js_AllocGCThing(cx, gcflag | GCX_STRING);
+    str = (JSString *) js_NewGCThing(cx, gcflag | GCX_STRING, sizeof(JSString));
     if (!str)
         return NULL;
     str->length = length;
@@ -2462,13 +2553,17 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start,
     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_AllocGCThing(cx, gcflag | GCX_MUTABLE_STRING);
+    ds = (JSDependentString *)
+         js_NewGCThing(cx, gcflag | GCX_MUTABLE_STRING, sizeof(JSString));
     if (!ds)
         return NULL;
     if (start == 0) {
@@ -2574,7 +2669,7 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag)
 JS_STATIC_DLL_CALLBACK(JSHashNumber)
 js_hash_string_pointer(const void *key)
 {
-    return (JSHashNumber)key >> JSVAL_TAGBITS;
+    return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
 }
 
 void
@@ -2635,13 +2730,31 @@ js_StringToObject(JSContext *cx, JSString *str)
 {
     JSObject *obj;
 
-    obj = js_NewObject(cx, &string_class, NULL, NULL);
+    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)
 {
@@ -2672,6 +2785,9 @@ js_ValueToString(JSContext *cx, jsval v)
 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)) {
@@ -2682,14 +2798,19 @@ js_ValueToSource(JSContext *cx, jsval v)
 
             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 {
-        if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v),
-                          cx->runtime->atomState.toSourceAtom,
-                          0, NULL, &v)) {
-            return NULL;
-        }
+        str = js_ValueToString(cx, tvr.u.value);
     }
-    return js_ValueToString(cx, v);
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return str;
 }
 
 JSHashNumber
@@ -2764,32 +2885,257 @@ js_SkipWhiteSpace(const jschar *s)
     return s;
 }
 
-#define INFLATE_STRING_BODY                                                   \
-    for (i = 0; i < length; i++)                                              \
-        chars[i] = (unsigned char) bytes[i];                                  \
-    chars[i] = 0;
+#ifdef JS_C_STRINGS_ARE_UTF8
 
-void
-js_InflateStringToBuffer(jschar *chars, const char *bytes, size_t length)
+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;
 
-    INFLATE_STRING_BODY
+    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 length)
+js_InflateString(JSContext *cx, const char *bytes, size_t *bytesLength)
 {
     jschar *chars;
-    size_t i;
+    size_t i, length = *bytesLength;
 
     chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
-    if (!chars)
+    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;
+}
 
-    INFLATE_STRING_BODY
+JSBool
+js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, size_t length,
+                         char *bytes, size_t* bytesLength)
+{
+    size_t i;
 
-    return chars;
+    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;
 }
 
 /*
@@ -2805,12 +3151,16 @@ js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
     bytes = (char *) (cx ? JS_malloc(cx, size) : malloc(size));
     if (!bytes)
         return NULL;
+
     for (i = 0; i < length; i++)
         bytes[i] = (char) chars[i];
-    bytes[i] = 0;
+
+    bytes[length] = 0;
     return bytes;
 }
 
+#endif /* !JS_C_STRINGS_ARE_UTF8 */
+
 static JSHashTable *
 GetDeflatedStringCache(void)
 {
@@ -2879,7 +3229,7 @@ js_GetStringBytes(JSString *str)
                       *bytes == (char) JSSTRING_CHARS(str)[0]);
         } else {
             bytes = js_DeflateString(NULL, JSSTRING_CHARS(str),
-                                     JSSTRING_LENGTH(str));
+                                           JSSTRING_LENGTH(str));
             if (bytes) {
                 if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
 #ifdef DEBUG
@@ -2936,7 +3286,9 @@ js_GetStringBytes(JSString *str)
  *                 character code, then masking with 0x1F, then adding 10
  *                 will produce the desired numeric value
  *  5 bits      digit offset
- *  4 bits      reserved for future use
+ *  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
  */
 
@@ -4066,119 +4418,119 @@ const uint32 js_A[] = {
 0x00000016,  /*    6   Pe */
 0x00000019,  /*    7   Sm */
 0x00000014,  /*    8   Pd */
-0x00036009,  /*    9   Nd, identifier part, decimal 16 */
-0x0827FE01,  /*   10   Lu, hasLower (add 32), identifier start, supradecimal 31 */
+0x00036089,  /*    9   Nd, identifier part, decimal 16 */
+0x0827FF81,  /*   10   Lu, hasLower (add 32), identifier start, supradecimal 31 */
 0x0000001B,  /*   11   Sk */
 0x00050017,  /*   12   Pc, underscore */
-0x0817FE02,  /*   13   Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
+0x0817FF82,  /*   13   Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
 0x0000000C,  /*   14   Zs */
 0x0000001C,  /*   15   So */
-0x00070002,  /*   16   Ll, identifier start */
+0x00070182,  /*   16   Ll, identifier start */
 0x0000600B,  /*   17   No, decimal 16 */
 0x0000500B,  /*   18   No, decimal 8 */
 0x0000800B,  /*   19   No, strange */
-0x08270001,  /*   20   Lu, hasLower (add 32), identifier start */
-0x08170002,  /*   21   Ll, hasUpper (subtract 32), identifier start */
-0xE1D70002,  /*   22   Ll, hasUpper (subtract -121), identifier start */
-0x00670001,  /*   23   Lu, hasLower (add 1), identifier start */
-0x00570002,  /*   24   Ll, hasUpper (subtract 1), identifier start */
-0xCE670001,  /*   25   Lu, hasLower (add -199), identifier start */
-0x3A170002,  /*   26   Ll, hasUpper (subtract 232), identifier start */
-0xE1E70001,  /*   27   Lu, hasLower (add -121), identifier start */
-0x4B170002,  /*   28   Ll, hasUpper (subtract 300), identifier start */
-0x34A70001,  /*   29   Lu, hasLower (add 210), identifier start */
-0x33A70001,  /*   30   Lu, hasLower (add 206), identifier start */
-0x33670001,  /*   31   Lu, hasLower (add 205), identifier start */
-0x32A70001,  /*   32   Lu, hasLower (add 202), identifier start */
-0x32E70001,  /*   33   Lu, hasLower (add 203), identifier start */
-0x33E70001,  /*   34   Lu, hasLower (add 207), identifier start */
-0x34E70001,  /*   35   Lu, hasLower (add 211), identifier start */
-0x34670001,  /*   36   Lu, hasLower (add 209), identifier start */
-0x35670001,  /*   37   Lu, hasLower (add 213), identifier start */
-0x00070001,  /*   38   Lu, identifier start */
-0x36A70001,  /*   39   Lu, hasLower (add 218), identifier start */
-0x00070005,  /*   40   Lo, identifier start */
-0x36670001,  /*   41   Lu, hasLower (add 217), identifier start */
-0x36E70001,  /*   42   Lu, hasLower (add 219), identifier start */
-0x00AF0001,  /*   43   Lu, hasLower (add 2), hasTitle, identifier start */
-0x007F0003,  /*   44   Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
-0x009F0002,  /*   45   Ll, hasUpper (subtract 2), hasTitle, identifier start */
+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 */
-0x34970002,  /*   47   Ll, hasUpper (subtract 210), identifier start */
-0x33970002,  /*   48   Ll, hasUpper (subtract 206), identifier start */
-0x33570002,  /*   49   Ll, hasUpper (subtract 205), identifier start */
-0x32970002,  /*   50   Ll, hasUpper (subtract 202), identifier start */
-0x32D70002,  /*   51   Ll, hasUpper (subtract 203), identifier start */
-0x33D70002,  /*   52   Ll, hasUpper (subtract 207), identifier start */
-0x34570002,  /*   53   Ll, hasUpper (subtract 209), identifier start */
-0x34D70002,  /*   54   Ll, hasUpper (subtract 211), identifier start */
-0x35570002,  /*   55   Ll, hasUpper (subtract 213), identifier start */
-0x36970002,  /*   56   Ll, hasUpper (subtract 218), identifier start */
-0x36570002,  /*   57   Ll, hasUpper (subtract 217), identifier start */
-0x36D70002,  /*   58   Ll, hasUpper (subtract 219), identifier start */
-0x00070004,  /*   59   Lm, identifier start */
-0x00030006,  /*   60   Mn, identifier part */
-0x09A70001,  /*   61   Lu, hasLower (add 38), identifier start */
-0x09670001,  /*   62   Lu, hasLower (add 37), identifier start */
-0x10270001,  /*   63   Lu, hasLower (add 64), identifier start */
-0x0FE70001,  /*   64   Lu, hasLower (add 63), identifier start */
-0x09970002,  /*   65   Ll, hasUpper (subtract 38), identifier start */
-0x09570002,  /*   66   Ll, hasUpper (subtract 37), identifier start */
-0x10170002,  /*   67   Ll, hasUpper (subtract 64), identifier start */
-0x0FD70002,  /*   68   Ll, hasUpper (subtract 63), identifier start */
-0x0F970002,  /*   69   Ll, hasUpper (subtract 62), identifier start */
-0x0E570002,  /*   70   Ll, hasUpper (subtract 57), identifier start */
-0x0BD70002,  /*   71   Ll, hasUpper (subtract 47), identifier start */
-0x0D970002,  /*   72   Ll, hasUpper (subtract 54), identifier start */
-0x15970002,  /*   73   Ll, hasUpper (subtract 86), identifier start */
-0x14170002,  /*   74   Ll, hasUpper (subtract 80), identifier start */
-0x14270001,  /*   75   Lu, hasLower (add 80), identifier start */
-0x0C270001,  /*   76   Lu, hasLower (add 48), identifier start */
-0x0C170002,  /*   77   Ll, hasUpper (subtract 48), identifier start */
-0x00034009,  /*   78   Nd, identifier part, decimal 0 */
-0x00000007,  /*   79   Me */
-0x00030008,  /*   80   Mc, identifier part */
-0x00037409,  /*   81   Nd, identifier part, decimal 26 */
+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 */
-0xFE170002,  /*   86   Ll, hasUpper (subtract -8), identifier start */
-0xFE270001,  /*   87   Lu, hasLower (add -8), identifier start */
-0xED970002,  /*   88   Ll, hasUpper (subtract -74), identifier start */
-0xEA970002,  /*   89   Ll, hasUpper (subtract -86), identifier start */
-0xE7170002,  /*   90   Ll, hasUpper (subtract -100), identifier start */
-0xE0170002,  /*   91   Ll, hasUpper (subtract -128), identifier start */
-0xE4170002,  /*   92   Ll, hasUpper (subtract -112), identifier start */
-0xE0970002,  /*   93   Ll, hasUpper (subtract -126), identifier start */
-0xFDD70002,  /*   94   Ll, hasUpper (subtract -9), identifier start */
-0xEDA70001,  /*   95   Lu, hasLower (add -74), identifier start */
-0xFDE70001,  /*   96   Lu, hasLower (add -9), identifier start */
-0xEAA70001,  /*   97   Lu, hasLower (add -86), identifier start */
-0xE7270001,  /*   98   Lu, hasLower (add -100), identifier start */
-0xFE570002,  /*   99   Ll, hasUpper (subtract -7), identifier start */
-0xE4270001,  /*  100   Lu, hasLower (add -112), identifier start */
-0xFE670001,  /*  101   Lu, hasLower (add -7), identifier start */
-0xE0270001,  /*  102   Lu, hasLower (add -128), identifier start */
-0xE0A70001,  /*  103   Lu, hasLower (add -126), identifier start */
+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 */
-0x0427420A,  /*  109   Nl, hasLower (add 16), identifier start, decimal 1 */
-0x0427800A,  /*  110   Nl, hasLower (add 16), identifier start, strange */
-0x0417620A,  /*  111   Nl, hasUpper (subtract 16), identifier start, decimal 17 */
-0x0417800A,  /*  112   Nl, hasUpper (subtract 16), identifier start, strange */
-0x0007800A,  /*  113   Nl, identifier start, strange */
+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 */
-0x0007720A,  /*  120   Nl, identifier start, decimal 25 */
-0x0007400A,  /*  121   Nl, identifier start, decimal 0 */
+0x0007738A,  /*  120   Nl, identifier start, decimal 25 */
+0x0007418A,  /*  121   Nl, identifier start, decimal 0 */
 0x00000013,  /*  122   Cs */
 0x00000012   /*  123   Co */
 };
@@ -4228,13 +4580,19 @@ 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;
+    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;
@@ -4242,21 +4600,20 @@ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
     hexBuf[0] = '%';
     hexBuf[3] = 0;
     chars = JSSTRING_CHARS(str);
-    length = JSSTRING_LENGTH(str);
     for (k = 0; k < length; k++) {
-        C = chars[k];
-        if (js_strchr(unescapedSet, C) ||
-            (unescapedSet2 && js_strchr(unescapedSet2, C))) {
-            if (!AddCharsToURI(cx, R, &C, 1))
+        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)) {
+            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;
+            if (c < 0xD800 || c > 0xDBFF) {
+                v = c;
             } else {
                 k++;
                 if (k == length) {
@@ -4264,15 +4621,15 @@ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
                                      JSMSG_BAD_URI, NULL);
                     return JS_FALSE;
                 }
-                C2 = chars[k];
-                if ((C2 < 0xDC00) || (C2 > 0xDFFF)) {
+                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;
+                v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
             }
-            L = OneUcs4ToUtf8Char(utf8buf, V);
+            L = js_OneUcs4ToUtf8Char(utf8buf, v);
             for (j = 0; j < L; j++) {
                 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
                 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
@@ -4298,22 +4655,27 @@ static JSBool
 Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
 {
     size_t length, start, k;
-    jschar *chars, C, H;
-    uint32 V;
+    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);
-    length = JSSTRING_LENGTH(str);
     for (k = 0; k < length; k++) {
-        C = chars[k];
-        if (C == '%') {
+        c = chars[k];
+        if (c == '%') {
             start = k;
             if ((k + 2) >= length)
                 goto bad;
@@ -4322,7 +4684,7 @@ Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
             B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
             k += 2;
             if (!(B & 0x80)) {
-                C = (jschar)B;
+                c = (jschar)B;
             } else {
                 n = 1;
                 while (B & (0x80 >> n))
@@ -4344,28 +4706,28 @@ Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
                     k += 2;
                     octets[j] = (char)B;
                 }
-                V = Utf8ToOneUcs4Char(octets, n);
-                if (V >= 0x10000) {
-                    V -= 0x10000;
-                    if (V > 0xFFFFF)
+                v = Utf8ToOneUcs4Char(octets, n);
+                if (v >= 0x10000) {
+                    v -= 0x10000;
+                    if (v > 0xFFFFF)
                         goto bad;
-                    C = (jschar)((V & 0x3FF) + 0xDC00);
-                    H = (jschar)((V >> 10) + 0xD800);
+                    c = (jschar)((v & 0x3FF) + 0xDC00);
+                    H = (jschar)((v >> 10) + 0xD800);
                     if (!AddCharsToURI(cx, R, &H, 1))
                         return JS_FALSE;
                 } else {
-                    C = (jschar)V;
+                    c = (jschar)v;
                 }
             }
-            if (js_strchr(reservedSet, C)) {
+            if (js_strchr(reservedSet, c)) {
                 if (!AddCharsToURI(cx, R, &chars[start], (k - start + 1)))
                     return JS_FALSE;
             } else {
-                if (!AddCharsToURI(cx, R, &C, 1))
+                if (!AddCharsToURI(cx, R, &c, 1))
                     return JS_FALSE;
             }
         } else {
-            if (!AddCharsToURI(cx, R, &C, 1))
+            if (!AddCharsToURI(cx, R, &c, 1))
                 return JS_FALSE;
         }
     }
@@ -4395,6 +4757,7 @@ str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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);
 }
 
@@ -4407,6 +4770,7 @@ str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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);
 }
 
@@ -4419,6 +4783,7 @@ str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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);
 }
@@ -4432,6 +4797,7 @@ str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     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);
 }
 
@@ -4439,8 +4805,8 @@ str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
  * least 6 bytes long.  Return the number of UTF-8 bytes of data written.
  */
-static int
-OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
+int
+js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
 {
     int utf8Length = 1;
 
@@ -4493,7 +4859,7 @@ Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
             JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
             ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
         }
-        if (ucs4Char < minucs4Char || 
+        if (ucs4Char < minucs4Char ||
             ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
             ucs4Char = 0xFFFD;
         }
index 202d0d9ea7c4571e7a91f8d0723c97279229870a..658a87f90f4c328b92274a546644fd1de011e42b 100644 (file)
@@ -210,44 +210,44 @@ typedef enum JSCharType {
 #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)
+                           (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)
+                           (1 << JSCT_LOWERCASE_LETTER) |                     \
+                           (1 << JSCT_TITLECASE_LETTER) |                     \
+                           (1 << JSCT_MODIFIER_LETTER) |                      \
+                           (1 << JSCT_OTHER_LETTER) |                         \
+                           (1 << JSCT_DECIMAL_DIGIT_NUMBER))                  \
+                          >> JS_CTYPE(c)) & 1)
 
 /* A unicode letter, suitable for use in an identifier. */
-#define JS_ISUC_LETTER(c)   ((((1 << JSCT_UPPERCASE_LETTER) |                 \
-                          (1 << JSCT_LOWERCASE_LETTER) |                     \
-                          (1 << JSCT_TITLECASE_LETTER) |                     \
-                          (1 << JSCT_MODIFIER_LETTER) |                      \
-                          (1 << JSCT_OTHER_LETTER) |                         \
-                          (1 << JSCT_LETTER_NUMBER))                         \
-                         >> JS_CTYPE(c)) & 1)
+#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_ISID_PART(c) ((((1 << JSCT_UPPERCASE_LETTER) |                     \
-                          (1 << JSCT_LOWERCASE_LETTER) |                     \
-                          (1 << JSCT_TITLECASE_LETTER) |                     \
-                          (1 << JSCT_MODIFIER_LETTER) |                      \
-                          (1 << JSCT_OTHER_LETTER) |                         \
-                          (1 << JSCT_LETTER_NUMBER) |                        \
-                          (1 << JSCT_NON_SPACING_MARK) |                     \
-                          (1 << JSCT_COMBINING_SPACING_MARK) |               \
-                          (1 << JSCT_DECIMAL_DIGIT_NUMBER) |                 \
-                          (1 << JSCT_CONNECTOR_PUNCTUATION))                 \
-                         >> JS_CTYPE(c)) & 1)
+#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)
@@ -259,12 +259,20 @@ typedef enum JSCharType {
  */
 #define JS_ISWORD(c)    ((c) < 128 && (isalnum(c) || (c) == '_'))
 
-/* XXXbe unify on A/X/Y tbls, avoid ctype.h? */
-#define JS_ISIDENT_START(c) (JS_ISUC_LETTER(c) || (c) == '_' || (c) == '$')
-#define JS_ISIDENT(c)       (JS_ISID_PART(c) || (c) == '_' || (c) == '$')
+#define JS_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))
@@ -279,8 +287,6 @@ typedef enum JSCharType {
                                    ? (c) + ((int32)JS_CCODE(c) >> 22)         \
                                    : (c)))
 
-#define JS_TOCTRL(c)    ((c) ^ 64)      /* XXX unsafe! requires uppercase c */
-
 /* Shorthands for ASCII (7-bit) decimal and hex conversion. */
 #define JS7_ISDEC(c)    ((c) < 128 && isdigit(c))
 #define JS7_UNDEC(c)    ((c) - '0')
@@ -306,6 +312,8 @@ 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);
 
@@ -344,6 +352,12 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str);
 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.
@@ -358,7 +372,7 @@ js_ValueToString(JSContext *cx, jsval v);
 extern JSString *
 js_ValueToSource(JSContext *cx, jsval v);
 
-#ifdef HT_ENUMERATE_NEXT       /* XXX don't require jshash.h */
+#ifdef HT_ENUMERATE_NEXT        /* XXX don't require jshash.h */
 /*
  * Compute a hash function from str.
  */
@@ -410,20 +424,33 @@ 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.
+ * 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);
+js_InflateString(JSContext *cx, const char *bytes, size_t *length);
 
 extern char *
 js_DeflateString(JSContext *cx, const jschar *chars, size_t length);
 
 /*
  * Inflate bytes to JS chars into a buffer.
- * 'chars' must be large enough for 'length'+1 jschars.
+ * '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 void
-js_InflateStringToBuffer(jschar *chars, const char *bytes, size_t length);
+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
@@ -443,6 +470,13 @@ 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___ */
index 35fc12e54bf78ae89e39ada032fbed66c1df7a7c..1c24293b5357795425131f29bfc0d5a87f138c31 100644 (file)
 #define JS_STATIC_DLL_CALLBACK(__x) __x JS_DLL_CALLBACK
 #endif /* _WINDLL */
 
-#elif defined(XP_MAC)
-#define JS_EXTERN_API(__type) extern __declspec(export) __type
-#define JS_EXPORT_API(__type) __declspec(export) __type
-#define JS_EXTERN_DATA(__type) extern __declspec(export) __type
-#define JS_EXPORT_DATA(__type) __declspec(export) __type
-
-#define JS_DLL_CALLBACK
-#define JS_STATIC_DLL_CALLBACK(__x) static __x
-
 #else /* Unix */
 
-#define JS_EXTERN_API(__type) extern __type
-#define JS_EXPORT_API(__type) __type
-#define JS_EXTERN_DATA(__type) extern __type
-#define JS_EXPORT_DATA(__type) __type
+#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
 #if defined(_WIN32) && !defined(__MWERKS__) && !defined(__GNUC__)
 #    define JS_IMPORT_DATA(__x)      __declspec(dllimport) __x
 #else
-#    define JS_IMPORT_DATA(__x)     __x
+#    define JS_IMPORT_DATA(__x)     JS_EXPORT_DATA (__x)
 #endif
 
 /*
 #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
 #define JS_MIN(x,y)     ((x)<(y)?(x):(y))
 #define JS_MAX(x,y)     ((x)>(y)?(x):(y))
 
-#if (defined(XP_MAC) || defined(XP_WIN)) && !defined(CROSS_COMPILE)
+#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_MAC, XP_OS2, XP_WIN or XP_UNIX"
+#    error "Must define one of XP_BEOS, XP_OS2, XP_WIN or XP_UNIX"
 #endif
 
 JS_BEGIN_EXTERN_C
@@ -382,7 +392,30 @@ 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___ */
-
index 6e4c21cade88373a10a1c3b9266732f1b0001a2d..d7fab0f88fb8cef4b412d4f1f7665864f3a5ed67 100644 (file)
 #    include <windows.h>
 #endif
 
-#ifdef XP_MAC
-#    include <Types.h>
-#    include <stdarg.h>
-#    include "jsprf.h"
+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();
+}
 
-#ifdef XP_MAC
-/*
- * PStrFromCStr converts the source C string to a destination
- * pascal string as it copies. The dest string will
- * be truncated to fit into an Str255 if necessary.
- * If the C String pointer is NULL, the pascal string's length is
- * set to zero.
- */
-static void PStrFromCStr(const char *src, Str255 dst)
+#if defined DEBUG_notme && defined XP_UNIX
+
+#define __USE_GNU 1
+#include <dlfcn.h>
+#include <setjmp.h>
+#include <string.h>
+#include "jshash.h"
+#include "jsprf.h"
+
+JSCallsite js_calltree_root = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL};
+
+static JSCallsite *
+CallTree(uint32 *bp)
 {
-    short length = 0;
-
-    /* handle case of overlapping strings */
-    if ( (void*)src == (void*)dst )
-    {
-        unsigned char *curdst = &dst[1];
-        unsigned char thisChar;
-
-        thisChar = *(const unsigned char*)src++;
-        while ( thisChar != '\0' )
-        {
-            unsigned char nextChar;
-
-            /*
-             * Use nextChar so we don't overwrite what we
-             * are about to read
-             */
-            nextChar = *(const unsigned char*)src++;
-            *curdst++ = thisChar;
-            thisChar = nextChar;
-
-            if ( ++length >= 255 )
-                break;
-        }
+    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;
     }
-    else if ( src != NULL )
-    {
-        unsigned char *curdst = &dst[1];
-        /* count down so test it loop is faster */
-        short overflow = 255;
-        register char temp;
 
-        /*
-         * Can't do the K&R C thing of while (*s++ = *t++)
-         * because it will copy trailing zero which might
-         * overrun pascal buffer.  Instead we use a temp variable.
-         */
-        while ( (temp = *src++) != 0 )
-        {
-            *(char*)curdst++ = temp;
+    /* 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;
+        }
 
-            if ( --overflow <= 0 )
-                break;
+        /* Check for recursion: see if pc is on our ancestor line. */
+        for (site = parent; site; site = site->parent) {
+            if (site->pc == pc)
+                goto upward;
         }
-        length = 255 - overflow;
-    }
-    dst[0] = length;
-}
 
-static void jsdebugstr(const char *debuggerMsg)
-{
-    Str255 pStr;
+        /*
+         * 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;
+        }
 
-    PStrFromCStr(debuggerMsg, pStr);
-    DebugStr(pStr);
+/* 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;
 }
 
-static void dprintf(const char *format, ...)
+JSCallsite *
+JS_Backtrace(int skip)
 {
-    va_list ap;
-    char *buffer;
-
-    va_start(ap, format);
-    buffer = (char *)JS_vsmprintf(format, ap);
-    va_end(ap);
+    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;
+    }
 
-    jsdebugstr(buffer);
-    JS_smprintf_free(buffer);
+    return CallTree(bp);
 }
-#endif   /* XP_MAC */
 
-JS_PUBLIC_API(void) JS_Assert(const char *s, const char *file, JSIntn ln)
-{
-#ifdef XP_MAC
-    dprintf("Assertion failure: %s, at %s:%d\n", s, file, ln);
-#else
-    fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
-#endif
-#if defined(WIN32)
-    DebugBreak();
-#endif
-#if defined(XP_OS2)
-    asm("int $3");
-#endif
-#ifndef XP_MAC
-    abort();
-#endif
-}
+#endif /* DEBUG_notme && XP_UNIX */
index a34096d9351d2f6f703472e267912a30f7511471..5e26c16ae3128d6601be3675dd7e6cdcdd28168f 100644 (file)
@@ -70,6 +70,25 @@ JS_Assert(const char *s, const char *file, JSIntn ln);
 */
 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___ */
index e956072f9a32b0c629caa48972656fc81413829e..0c9aeceedf01acea39ccf618ff4b3e03a4a16fe4 100644 (file)
@@ -498,7 +498,7 @@ 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;
diff --git a/src/dom/js/jsxml.c b/src/dom/js/jsxml.c
new file mode 100644 (file)
index 0000000..e7cde2e
--- /dev/null
@@ -0,0 +1,8295 @@
+/* -*- 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <string.h>     /* 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[]    = "&amp;";
+const char js_gt_entity_str[]     = "&gt;";
+const char js_lt_entity_str[]     = "&lt;";
+const char js_quot_entity_str[]   = "&quot;";
+
+#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
+ *   <parent xmlns='...'> 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
+         * <parent xmlns='%s'>...</parent> 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[] = "<parent xmlns='";
+    static const char middle[] = "'>";
+    static const char suffix[] = "</parent>";
+
+#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, "&#xA;");
+            else if (c == '\r')
+                js_AppendCString(sb, "&#xD;");
+            else if (c == '\t')
+                js_AppendCString(sb, "&#x9;");
+            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 = <t xmlns="http://foo.com"/>
+             *   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 = &empty;
+    }
+    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, "</");
+
+        /* Step 26. */
+        if (ns->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, &copy->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, &copy->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(&copy->xml_namespaces, i, ns2);
+            }
+
+            ok = DeepCopySetInLRS(cx, &xml->xml_attrs, &copy->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("<TEAM>Giants</TEAM>"));
+                     *
+                     * (testcase from Werner Sharp <wsharp@macromedia.com>).
+                     *
+                     * 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, &copy->xml_kids, n);
+                if (!ok)
+                    goto out;
+                for (k = 0; k < n; k++) {
+                    kid2 = XMLARRAY_MEMBER(&vxml->xml_kids, k, JSXML);
+                    XMLARRAY_SET_MEMBER(&copy->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(&copy->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
new file mode 100644 (file)
index 0000000..294e66c
--- /dev/null
@@ -0,0 +1,329 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF 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___ */
index 774f83999c41cdadce4551f758ccaf517d41df4f..6e08423af8009f17137540d2d915de8d855c332f 100644 (file)
 #include <winbase.h>
 #endif
 
-#ifdef XP_MAC
-#include <OSUtils.h>
-#include <TextUtils.h>
-#include <Resources.h>
-#include <Timer.h>
-#include <UTCUtils.h>
-#include <Power.h>
-#include <CodeFragments.h>
-#if !TARGET_CARBON
-#include <Traps.h>
-#endif
-#endif
-
 #if defined(XP_UNIX) || defined(XP_BEOS)
 
 #ifdef _SVID_GETTOD   /* Defined only on Solaris, see Solaris <sys/types.h> */
@@ -85,128 +72,6 @@ extern int gettimeofday(struct timeval *tv);
 
 #endif /* XP_UNIX */
 
-#ifdef XP_MAC
-static uint64                   dstLocalBaseMicroseconds;
-static unsigned long    gJanuaryFirst1970Seconds;
-
-static void MacintoshInitializeTime(void)
-{
-    uint64                                     upTime;
-    unsigned long                      currentLocalTimeSeconds,
-          startupTimeSeconds;
-    uint64                             startupTimeMicroSeconds;
-    uint32                             upTimeSeconds;
-    uint64                             oneMillion, upTimeSecondsLong, microSecondsToSeconds;
-    DateTimeRec                                firstSecondOfUnixTime;
-
-    /*
-     * Figure out in local time what time the machine started up. This information can be added to
-     * upTime to figure out the current local time as well as GMT.
-     */
-
-    Microseconds((UnsignedWide*)&upTime);
-
-    GetDateTime(&currentLocalTimeSeconds);
-
-    JSLL_I2L(microSecondsToSeconds, PRMJ_USEC_PER_SEC);
-    JSLL_DIV(upTimeSecondsLong, upTime, microSecondsToSeconds);
-    JSLL_L2I(upTimeSeconds, upTimeSecondsLong);
-
-    startupTimeSeconds = currentLocalTimeSeconds - upTimeSeconds;
-
-    /*  Make sure that we normalize the macintosh base seconds to the unix base of January 1, 1970.
-     */
-
-    firstSecondOfUnixTime.year = 1970;
-    firstSecondOfUnixTime.month = 1;
-    firstSecondOfUnixTime.day = 1;
-    firstSecondOfUnixTime.hour = 0;
-    firstSecondOfUnixTime.minute = 0;
-    firstSecondOfUnixTime.second = 0;
-    firstSecondOfUnixTime.dayOfWeek = 0;
-
-    DateToSeconds(&firstSecondOfUnixTime, &gJanuaryFirst1970Seconds);
-
-    startupTimeSeconds -= gJanuaryFirst1970Seconds;
-
-    /*  Now convert the startup time into a wide so that we can figure out GMT and DST.
-     */
-
-    JSLL_I2L(startupTimeMicroSeconds, startupTimeSeconds);
-    JSLL_I2L(oneMillion, PRMJ_USEC_PER_SEC);
-    JSLL_MUL(dstLocalBaseMicroseconds, oneMillion, startupTimeMicroSeconds);
-}
-
-static SleepQRec  gSleepQEntry = { NULL, sleepQType, NULL, 0 };
-static JSBool     gSleepQEntryInstalled = JS_FALSE;
-
-static pascal long MySleepQProc(long message, SleepQRecPtr sleepQ)
-{
-    /* just woke up from sleeping, so must recompute dstLocalBaseMicroseconds. */
-    if (message == kSleepWakeUp)
-        MacintoshInitializeTime();
-    return 0;
-}
-
-/* Because serial port and SLIP conflict with ReadXPram calls,
- * we cache the call here
- */
-
-static void MyReadLocation(MachineLocation * loc)
-{
-    static MachineLocation storedLoc;  /* InsideMac, OSUtilities, page 4-20 */
-    static JSBool didReadLocation = JS_FALSE;
-    if (!didReadLocation)
-    {
-        MacintoshInitializeTime();
-        ReadLocation(&storedLoc);
-        /* install a sleep queue routine, so that when the machine wakes up, time can be recomputed. */
-        if (&SleepQInstall != (void*)kUnresolvedCFragSymbolAddress
-#if !TARGET_CARBON
-            && NGetTrapAddress(0xA28A, OSTrap) != NGetTrapAddress(_Unimplemented, ToolTrap)
-#endif
-           ) {
-            if ((gSleepQEntry.sleepQProc = NewSleepQUPP(MySleepQProc)) != NULL) {
-                SleepQInstall(&gSleepQEntry);
-                gSleepQEntryInstalled = JS_TRUE;
-            }
-        }
-        didReadLocation = JS_TRUE;
-     }
-     *loc = storedLoc;
-}
-
-
-#ifndef XP_MACOSX
-
-/* CFM library init and terminate routines. We'll use the terminate routine
-   to clean up the sleep Q entry. On Mach-O, the sleep Q entry gets cleaned
-   up for us, so nothing to do there.
-*/
-
-extern pascal OSErr __NSInitialize(const CFragInitBlock* initBlock);
-extern pascal void __NSTerminate();
-
-pascal OSErr __JSInitialize(const CFragInitBlock* initBlock);
-pascal void __JSTerminate(void);
-
-pascal OSErr __JSInitialize(const CFragInitBlock* initBlock)
-{
-       return __NSInitialize(initBlock);
-}
-
-pascal void __JSTerminate()
-{
-  /* clean up the sleepQ entry */
-  if (gSleepQEntryInstalled)
-    SleepQRemove(&gSleepQEntry);
-
-       __NSTerminate();
-}
-#endif /* XP_MACOSX */
-
-#endif /* XP_MAC */
-
 #define IS_LEAP(year) \
    (year != 0 && ((((year & 0x3) == 0) &&  \
                   ((year - ((year/100) * 100)) != 0)) || \
@@ -239,32 +104,6 @@ PRMJ_LocalGMTDifference()
     return mktime(&ltime) - (24L * 3600L);
 #endif
 #endif
-#if defined(XP_MAC)
-    static JSInt32   zone = -1L;
-    MachineLocation  machineLocation;
-    JSInt32         gmtOffsetSeconds;
-
-    /* difference has been set no need to recalculate */
-    if (zone != -1)
-        return zone;
-
-    /* Get the information about the local machine, including
-     * its GMT offset and its daylight savings time info.
-     * Convert each into wides that we can add to
-     * startupTimeMicroSeconds.
-     */
-
-    MyReadLocation(&machineLocation);
-
-    /* Mask off top eight bits of gmtDelta, sign extend lower three. */
-    gmtOffsetSeconds = (machineLocation.u.gmtDelta << 8);
-    gmtOffsetSeconds >>= 8;
-
-    /* Backout OS adjustment for DST, to give consistent GMT offset. */
-    if (machineLocation.u.dlsDelta != 0)
-        gmtOffsetSeconds -= PRMJ_HOUR_SECONDS;
-    return (zone = -gmtOffsetSeconds);
-#endif
 }
 
 /* Constants for GMT offset from 1970 */
@@ -323,14 +162,6 @@ PRMJ_Now(void)
     struct timeval tv;
     JSInt64 s, us, s2us;
 #endif /* XP_UNIX */
-#ifdef XP_MAC
-    JSUint64 upTime;
-    JSInt64     localTime;
-    JSInt64       gmtOffset;
-    JSInt64    dstOffset;
-    JSInt32       gmtDiff;
-    JSInt64     s2us;
-#endif /* XP_MAC */
 
 #ifdef XP_OS2
     ftime(&b);
@@ -378,24 +209,6 @@ PRMJ_Now(void)
     JSLL_ADD(s, s, us);
     return s;
 #endif /* XP_UNIX */
-#ifdef XP_MAC
-    JSLL_UI2L(localTime,0);
-    gmtDiff = PRMJ_LocalGMTDifference();
-    JSLL_I2L(gmtOffset,gmtDiff);
-    JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
-    JSLL_MUL(gmtOffset,gmtOffset,s2us);
-
-    /* don't adjust for DST since it sets ctime and gmtime off on the MAC */
-    Microseconds((UnsignedWide*)&upTime);
-    JSLL_ADD(localTime,localTime,gmtOffset);
-    JSLL_ADD(localTime,localTime, dstLocalBaseMicroseconds);
-    JSLL_ADD(localTime,localTime, upTime);
-
-    dstOffset = PRMJ_DSTOffset(localTime);
-    JSLL_SUB(localTime,localTime,dstOffset);
-
-    return *((JSUint64 *)&localTime);
-#endif /* XP_MAC */
 }
 
 /* Get the DST timezone offset for the time passed in */
@@ -403,24 +216,6 @@ JSInt64
 PRMJ_DSTOffset(JSInt64 local_time)
 {
     JSInt64 us2s;
-#ifdef XP_MAC
-    /*
-     * Convert the local time passed in to Macintosh epoch seconds. Use UTC utilities to convert
-     * to UTC time, then compare difference with our GMT offset. If they are the same, then
-     * DST must not be in effect for the input date/time.
-     */
-    UInt32 macLocalSeconds = (local_time / PRMJ_USEC_PER_SEC) + gJanuaryFirst1970Seconds, utcSeconds;
-    ConvertLocalTimeToUTC(macLocalSeconds, &utcSeconds);
-    if ((utcSeconds - macLocalSeconds) == PRMJ_LocalGMTDifference())
-        return 0;
-    else {
-        JSInt64 dlsOffset;
-       JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC);
-       JSLL_UI2L(dlsOffset, PRMJ_HOUR_SECONDS);
-       JSLL_MUL(dlsOffset, dlsOffset, us2s);
-        return dlsOffset;
-    }
-#else
     time_t local;
     JSInt32 diff;
     JSInt64  maxtimet;
@@ -467,14 +262,13 @@ PRMJ_DSTOffset(JSInt64 local_time)
     JSLL_MUL(local_time,local_time,us2s);
 
     return(local_time);
-#endif
 }
 
 /* Format a time value into a buffer. Same semantics as strftime() */
 size_t
 PRMJ_FormatTime(char *buf, int buflen, char *fmt, PRMJTime *prtm)
 {
-#if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_MAC) || defined(XP_BEOS)
+#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
index 6a94a11b1673f5377a8334b4b1a4060f33f2177c..b74fe845eb67a8c19dd313c06f48d7ae56891898 100644 (file)
@@ -57,21 +57,21 @@ 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 */
+    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
+#define PRMJ_USEC_PER_SEC       1000000L
+#define PRMJ_USEC_PER_MSEC      1000L
 
 /* Return the current local time in micro-seconds */
 extern JSInt64