summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 009821f)
raw | patch | inline | side by side (parent: 009821f)
author | ishmal <ishmal@users.sourceforge.net> | |
Mon, 5 Mar 2007 10:34:59 +0000 (10:34 +0000) | ||
committer | ishmal <ishmal@users.sourceforge.net> | |
Mon, 5 Mar 2007 10:34:59 +0000 (10:34 +0000) |
93 files changed:
diff --git a/src/dom/Makefile.mingw b/src/dom/Makefile.mingw
index 33b6aed9eb794c8ee5c51a754d8c103ecf34e93a..b47437265f13e9ff80bd76af91f28c4c15fd4985 100644 (file)
--- a/src/dom/Makefile.mingw
+++ b/src/dom/Makefile.mingw
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
--- /dev/null
+++ b/src/dom/js/README.ink
@@ -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
+++ /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
+++ /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
+++ /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)
#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
+++ /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 5904c49..0000000
Binary files a/src/dom/js/fdlibm/fdlibm.mdp and /dev/null differ
index 17b505d5880b29a4998fb0045d012929650192b5..1d18c803433fa37d440bac9c85858b2f9e9e4081 100644 (file)
#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*/
diff --git a/src/dom/js/js.c b/src/dom/js/js.c
index 77c778b9277ba30684f7c168aa76eaaefc6c8e8d..b3961667061d0e888244e3e0f5d9af5382455683 100644 (file)
--- a/src/dom/js/js.c
+++ b/src/dom/js/js.c
/* -*- 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;
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
#endif /* JSDEBUGGER */
static JSBool reportWarnings = JS_TRUE;
+static JSBool compileOnly = JS_FALSE;
typedef enum JSShellErrNum {
#define MSG_DEF(name, number, count, exception, format) \
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);
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;
/* 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);
}
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;
}
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;
}
case 'b':
case 'c':
case 'f':
+ case 'e':
case 'v':
case 'S':
++i;
break;
+ default:;
}
}
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;
case 'b':
gBranchLimit = atoi(argv[++i]);
JS_SetBranchCallback(cx, my_BranchCallback);
+ JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK);
break;
case 'c':
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();
{"strict", JSOPTION_STRICT},
{"werror", JSOPTION_WERROR},
{"atline", JSOPTION_ATLINE},
+ {"xml", JSOPTION_XML},
{0, 0}
};
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);
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)
{
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)
{
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 {
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);
}
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++;
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);
}
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},
{"untrap", Untrap, 2},
{"line2pc", LineToPC, 0},
{"pc2line", PCToLine, 0},
+ {"stringsAreUtf8", StringsAreUtf8, 0},
+ {"testUtf8", TestUtf8, 1},
#ifdef DEBUG
{"dis", Disassemble, 1},
{"dissrc", DisassWithSrc, 1},
{"intern", Intern, 1},
{"clone", Clone, 1},
{"seal", Seal, 1, 0, 1},
+ {"getpda", GetPDA, 1},
+ {"getslx", GetSLX, 1},
+ {"toint32", ToInt32, 1},
{0}
};
"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",
"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",
"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
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}
};
}
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);
}
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;
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;
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';
main(int argc, char **argv, char **envp)
{
int stackDummy;
- JSVersion version;
JSRuntime *rt;
JSContext *cx;
JSObject *glob, *it, *envobj;
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++;
if (!JS_DefineFunctions(cx, glob, shell_functions))
return 1;
- /* Set version only after there is a global object. */
- if (version != JSVERSION_DEFAULT)
- JS_SetVersion(cx, version);
-
it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0);
if (!it)
return 1;
if (!JS_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)) {
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
--- a/src/dom/js/js.mak
+++ /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
diff --git a/src/dom/js/js.msg b/src/dom/js/js.msg
index dc6c534f7cce89dbfc749fe5d1ba06a3ef0549d7..5df1ead9e23bf7a9905f6f2463230aab0fc33a4a 100644 (file)
--- a/src/dom/js/js.msg
+++ b/src/dom/js/js.msg
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")
MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode JSPrincipals")
MSG_DEF(JSMSG_CANT_SEAL_OBJECT, 168, 1, JSEXN_ERR, "can't seal {0} objects")
MSG_DEF(JSMSG_CANT_UNSEAL_OBJECT, 169, 1, JSEXN_ERR, "can't unseal {0} objects")
+MSG_DEF(JSMSG_BAD_XML_MARKUP, 170, 0, JSEXN_SYNTAXERR, "invalid XML markup")
+MSG_DEF(JSMSG_BAD_XML_CHARACTER, 171, 0, JSEXN_SYNTAXERR, "illegal XML character")
+MSG_DEF(JSMSG_BAD_DEFAULT_XML_NAMESPACE,172,0,JSEXN_SYNTAXERR, "invalid default XML namespace")
+MSG_DEF(JSMSG_BAD_XML_NAME_SYNTAX, 173, 0, JSEXN_SYNTAXERR, "invalid XML name")
+MSG_DEF(JSMSG_BRACKET_AFTER_ATTR_EXPR,174, 0, JSEXN_SYNTAXERR, "missing ] after attribute expression")
+MSG_DEF(JSMSG_NAME_AFTER_DBLDOT, 175, 0, JSEXN_SYNTAXERR, "missing name after .. operator")
+MSG_DEF(JSMSG_CURLY_IN_XML_EXPR, 176, 0, JSEXN_SYNTAXERR, "missing } in XML expression")
+MSG_DEF(JSMSG_BAD_XML_NAMESPACE, 177, 1, JSEXN_TYPEERR, "invalid XML namespace {0}")
+MSG_DEF(JSMSG_BAD_XML_ATTR_NAME, 178, 1, JSEXN_TYPEERR, "invalid XML attribute name {0}")
+MSG_DEF(JSMSG_BAD_XML_NAME, 179, 1, JSEXN_TYPEERR, "invalid XML name {0}")
+MSG_DEF(JSMSG_BAD_XML_CONVERSION, 180, 1, JSEXN_TYPEERR, "can't convert {0} to XML")
+MSG_DEF(JSMSG_BAD_XMLLIST_CONVERSION, 181, 1, JSEXN_TYPEERR, "can't convert {0} to XMLList")
+MSG_DEF(JSMSG_IS_NOT_XML_OBJECT, 182, 1, JSEXN_TYPEERR, "{0} is not an XML object")
+MSG_DEF(JSMSG_NO_ASSIGN_IN_XML_ATTR, 183, 0, JSEXN_SYNTAXERR, "missing = in XML attribute")
+MSG_DEF(JSMSG_BAD_XML_ATTR_VALUE, 184, 0, JSEXN_SYNTAXERR, "invalid XML attribute value")
+MSG_DEF(JSMSG_XML_TAG_NAME_MISMATCH, 185, 0, JSEXN_SYNTAXERR, "XML tag name mismatch")
+MSG_DEF(JSMSG_BAD_XML_TAG_SYNTAX, 186, 0, JSEXN_SYNTAXERR, "invalid XML tag syntax")
+MSG_DEF(JSMSG_BAD_XML_LIST_SYNTAX, 187, 0, JSEXN_SYNTAXERR, "invalid XML list syntax")
+MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
+MSG_DEF(JSMSG_CANT_SET_XML_ATTRS, 189, 0, JSEXN_INTERNALERR, "can't set XML property attributes")
+MSG_DEF(JSMSG_END_OF_XML_SOURCE, 190, 0, JSEXN_SYNTAXERR, "unexpected end of XML source")
+MSG_DEF(JSMSG_END_OF_XML_ENTITY, 191, 0, JSEXN_SYNTAXERR, "unexpected end of XML entity")
+MSG_DEF(JSMSG_BAD_XML_QNAME, 192, 0, JSEXN_SYNTAXERR, "invalid XML qualified name")
+MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop")
+MSG_DEF(JSMSG_BAD_XMLLIST_PUT, 194, 1, JSEXN_TYPEERR, "can't set property {0} in XMLList")
+MSG_DEF(JSMSG_UNKNOWN_XML_ENTITY, 195, 1, JSEXN_TYPEERR, "unknown XML entity {0}")
+MSG_DEF(JSMSG_BAD_XML_NCR, 196, 1, JSEXN_TYPEERR, "malformed XML character {0}")
+MSG_DEF(JSMSG_UNDEFINED_XML_NAME, 197, 1, JSEXN_REFERENCEERR, "reference to undefined XML name {0}")
+MSG_DEF(JSMSG_DUPLICATE_XML_ATTR, 198, 1, JSEXN_TYPEERR, "duplicate XML attribute {0}")
+MSG_DEF(JSMSG_TOO_MANY_FUN_VARS, 199, 0, JSEXN_SYNTAXERR, "too many local variables")
+MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 200, 0, JSEXN_INTERNALERR, "array initialiser too large")
+MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX, 201, 0, JSEXN_INTERNALERR, "regular expression too complex")
+MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 202, 1, JSEXN_TYPEERR, "wrong construtor called for {0}")
+MSG_DEF(JSMSG_SELF_MODIFYING_SCRIPT, 203, 0, JSEXN_TYPEERR, "self-modifying script detected")
+MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 204, 0, JSEXN_INTERNALERR, "buffer too small")
+MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 205, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
+MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 206, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
+MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 207, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
+MSG_DEF(JSMSG_USER_DEFINED_ERROR, 208, 0, JSEXN_ERR, "JS_ReportError was called")
diff --git a/src/dom/js/jsapi.c b/src/dom/js/jsapi.c
index 5b7200a49075b89333aa148d0634511405b4293b..344fc24690ad3413d68181e4522ff44f554e58b3 100644 (file)
--- a/src/dom/js/jsapi.c
+++ b/src/dom/js/jsapi.c
/* -*- 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
*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;
{
JSBool ok, b;
JSObject *obj;
- JSFunction *fun;
JSString *str;
jsdouble d, *dp;
*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);
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);
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;
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;
}
#endif
+ js_FreeRuntimeScriptState(rt);
js_FinishAtomState(&rt->atomState);
js_FinishGC(rt);
#ifdef JS_THREADSAFE
JS_PUBLIC_API(JSVersion)
JS_GetVersion(JSContext *cx)
{
- return cx->version;
+ return cx->version & JSVERSION_MASK;
}
JS_PUBLIC_API(JSVersion)
{
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;
}
{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 */
};
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;
}
{
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";
}
JS_SetGlobalObject(JSContext *cx, JSObject *obj)
{
cx->globalObject = obj;
+#if JS_HAS_XML_SUPPORT
+ cx->xmlSettingFlags = 0;
+#endif
}
static JSObject *
/* 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;
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);
}
{
/* 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;
}
}
#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);
}
#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}
};
{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}
};
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
}
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)
{
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
/* 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
JS_NewDouble(JSContext *cx, jsdouble d)
{
CHECK_REQUEST(cx);
- return js_NewDouble(cx, d);
+ return js_NewDouble(cx, d, 0);
}
JS_PUBLIC_API(JSBool)
for (i = 0; i < GCX_NTYPES; i++)
cx->newborn[i] = NULL;
cx->lastAtom = NULL;
+ cx->lastInternalResult = JSVAL_NULL;
}
JS_PUBLIC_API(JSBool)
JS_PUBLIC_API(void)
JS_MaybeGC(JSContext *cx)
{
+#ifdef WAY_TOO_MUCH_GC
+ JS_GC(cx);
+#else
JSRuntime *rt;
uint32 bytes, lastBytes;
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
*/
JS_GC(cx);
}
+#endif
}
JS_PUBLIC_API(JSGCCallback)
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)
{
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;
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;
atom = js_ValueToStringAtom(cx, v);
if (!atom)
return JS_FALSE;
- *idp = (jsid)atom;
+ *idp = ATOM_TO_JSID(atom);
}
return JS_TRUE;
}
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)
{
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);
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;
*/
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;
(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
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)
{
CHECK_REQUEST(cx);
if (!OBJ_GET_PROPERTY(cx, proto,
- (jsid)cx->runtime->atomState.constructorAtom,
+ ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
&cval)) {
return NULL;
}
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;
}
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,
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
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)
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)
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;
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;
}
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;
}
*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)
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)
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;
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)
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)
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)
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)
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)
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)
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 *)
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);
}
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)
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)
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;
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)
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)
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)
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)
}
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;
}
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;
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);
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,
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,
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;
}
JSErrorReporter older;
CHECK_REQUEST(cx);
- chars = js_InflateString(cx, bytes, length);
+ chars = js_InflateString(cx, bytes, &length);
if (!chars)
return JS_TRUE;
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);
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;
}
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;
}
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,
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,
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;
}
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;
}
}
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;
}
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)
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);
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,
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;
}
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)
{
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;
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);
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);
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)
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);
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
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
#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)
diff --git a/src/dom/js/jsapi.h b/src/dom/js/jsapi.h
index 8f491ffec363fc8b4e124ada0f170f9e49216259..9fe07ac601c590d33f7d8b6723773577fb8d9b84 100644 (file)
--- a/src/dom/js/jsapi.h
+++ b/src/dom/js/jsapi.h
#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).
option supported for the
XUL preprocessor and kindred
beasts. */
+#define JSOPTION_XML JS_BIT(6) /* EMCAScript for XML support:
+ parse <!-- --> as a token,
+ not backward compatible with
+ the comment-hiding hack used
+ in HTML script tags. */
+#define JSOPTION_NATIVE_BRANCH_CALLBACK \
+ JS_BIT(7) /* the branch callback set by
+ JS_SetBranchCallback may be
+ called with a null script
+ parameter, by native code
+ that loops intensively */
extern JS_PUBLIC_API(uint32)
JS_GetOptions(JSContext *cx);
extern JS_PUBLIC_API(JSBool)
JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj);
+/*
+ * Enumerate any already-resolved standard class ids into ida, or into a new
+ * JSIdArray if ida is null. Return the augmented array on success, null on
+ * failure with ida (if it was non-null on entry) destroyed.
+ */
+extern JS_PUBLIC_API(JSIdArray *)
+JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
+ JSIdArray *ida);
+
extern JS_PUBLIC_API(JSObject *)
JS_GetScopeChain(JSContext *cx);
extern JS_PUBLIC_API(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).
*
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 */
object in prototype chain
passed in via *objp in/out
parameter */
+#define JSCLASS_CONSTRUCT_PROTOTYPE (1<<6) /* call constructor on class
+ prototype */
+#define JSCLASS_DOCUMENT_OBSERVER (1<<7) /* DOM document observer */
/*
* To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
>> JSCLASS_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 {
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
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) ?...:...' */
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);
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.
*
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);
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.
*
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);
*/
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
JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px);
extern JS_PUBLIC_API(JSObjectPrincipalsFinder)
-JS_SetObjectPrincipalsFinder(JSContext *cx, JSObjectPrincipalsFinder fop);
+JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop);
/************************************************************************/
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
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);
+
/************************************************************************/
/*
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
/*
diff --git a/src/dom/js/jsarena.c b/src/dom/js/jsarena.c
index 2abcacd2b382eabcfa1486d6577c31ae3dbf8c8e..8b2c8a54115017532510b22fb756dd70fbb24557 100644 (file)
--- a/src/dom/js/jsarena.c
+++ b/src/dom/js/jsarena.c
@@ -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
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;
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,++);
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;
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;
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;
+ }
}
}
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
}
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);
diff --git a/src/dom/js/jsarena.h b/src/dom/js/jsarena.h
index e52398a1a822c81bad583801ac64e209b4b70b8d..5370f8f82686bd7ca033881785b6654dd63cddde 100644 (file)
--- a/src/dom/js/jsarena.h
+++ b/src/dom/js/jsarena.h
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
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); \
diff --git a/src/dom/js/jsarray.c b/src/dom/js/jsarray.c
index a05a6ee3c0c2854f15b6d3a45aed2b641ed7260c..ef94be4e52a2969d6ae83d42e0e17c4bbc71290d 100644 (file)
--- a/src/dom/js/jsarray.c
+++ b/src/dom/js/jsarray.c
/* -*- 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 "jsapi.h"
#include "jsarray.h"
#include "jsatom.h"
+#include "jsbool.h"
#include "jscntxt.h"
#include "jsconfig.h"
#include "jsfun.h"
#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):
*
* 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;
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)) {
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))))
*lengthp = (jsuint) i;
return JS_TRUE;
}
-
+
if (!js_ValueToNumber(cx, v, &d)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_ARRAY_LENGTH);
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)
{
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);
}
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;
}
/*
{
jsuint index, length;
- if (!(IdIsIndex(id, &index)))
+ if (!js_IdIsIndex(id, &index))
return JS_TRUE;
if (!js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
{
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);
}
}
/* 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)
}
sepstr = JSSTRING_CHARS(sep);
- tmplen = JSSTRING_LENGTH(str);
js_strncpy(&chars[nchars], JSSTRING_CHARS(str), tmplen);
nchars += tmplen;
}
return ok;
}
+#undef v
+
make_string:
if (!chars) {
JS_ReportOutOfMemory(cx);
* 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);
}
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]))
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,
{
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 {
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.
#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
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;
}
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:
* 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;
}
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;
/* 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;
}
}
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
/* 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}
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) {
diff --git a/src/dom/js/jsarray.h b/src/dom/js/jsarray.h
index cbb2aedf1aa3ea591b09ec5e88f7c69a5a0e9a5a..0f43bee079a08d9bb4f098b8150dc669aaf1805a 100644 (file)
--- a/src/dom/js/jsarray.h
+++ b/src/dom/js/jsarray.h
JS_BEGIN_EXTERN_C
+extern JSBool
+js_IdIsIndex(jsval id, jsuint *indexp);
+
extern JSClass js_ArrayClass;
extern JSObject *
*/
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
diff --git a/src/dom/js/jsatom.c b/src/dom/js/jsatom.c
index ede2350b6ec11e372bedfe2d54b6e54f46ca1487..6de628aefd54821ee3f8e537a1985af455caedae 100644 (file)
--- a/src/dom/js/jsatom.c
+++ b/src/dom/js/jsatom.c
#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
*/
const char *js_type_str[] = {
"undefined",
- "object",
+ js_object_str,
"function",
"string",
"number",
"boolean",
+ "null",
+ "xml",
};
const char *js_boolean_str[] = {
const char js_Date_str[] = "Date";
const char js_Function_str[] = "Function";
const char js_Math_str[] = "Math";
+const char js_Namespace_str[] = "Namespace";
const char js_Number_str[] = "Number";
const char js_Object_str[] = "Object";
+const char js_QName_str[] = "QName";
const char js_RegExp_str[] = "RegExp";
const char js_Script_str[] = "Script";
const char js_String_str[] = "String";
+const char js_XML_str[] = "XML";
+const char js_File_str[] = "File";
const char js_anonymous_str[] = "anonymous";
const char js_arguments_str[] = "arguments";
const char js_arity_str[] = "arity";
const char js_class_prototype_str[] = "prototype";
const char js_constructor_str[] = "constructor";
const char js_count_str[] = "__count__";
+const char js_each_str[] = "each";
const char js_eval_str[] = "eval";
const char js_getter_str[] = "getter";
const char js_get_str[] = "get";
const char js_length_str[] = "length";
const char js_name_str[] = "name";
const char js_noSuchMethod_str[] = "__noSuchMethod__";
+const char js_object_str[] = "object";
const char js_parent_str[] = "__parent__";
+const char js_private_str[] = "private";
const char js_proto_str[] = "__proto__";
const char js_setter_str[] = "setter";
const char js_set_str[] = "set";
const char js_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__";
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)
FROB(BooleanAtom, js_Boolean_str);
FROB(CallAtom, js_Call_str);
FROB(DateAtom, js_Date_str);
+#if JS_HAS_ERROR_EXCEPTIONS
FROB(ErrorAtom, js_Error_str);
+#endif
FROB(FunctionAtom, js_Function_str);
FROB(MathAtom, js_Math_str);
+ FROB(NamespaceAtom, js_Namespace_str);
FROB(NumberAtom, js_Number_str);
FROB(ObjectAtom, js_Object_str);
+ FROB(QNameAtom, js_QName_str);
FROB(RegExpAtom, js_RegExp_str);
FROB(ScriptAtom, js_Script_str);
FROB(StringAtom, js_String_str);
+ FROB(XMLAtom, js_XML_str);
+ FROB(FileAtom, js_File_str);
FROB(anonymousAtom, js_anonymous_str);
FROB(argumentsAtom, js_arguments_str);
FROB(arityAtom, js_arity_str);
FROB(classPrototypeAtom, js_class_prototype_str);
FROB(constructorAtom, js_constructor_str);
FROB(countAtom, js_count_str);
+ FROB(eachAtom, js_each_str);
FROB(evalAtom, js_eval_str);
FROB(getAtom, js_get_str);
FROB(getterAtom, js_getter_str);
FROB(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);
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;
}
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)
{
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);
}
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);
*/
#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;
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);
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);
diff --git a/src/dom/js/jsatom.h b/src/dom/js/jsatom.h
index 6f486c3371f6e548185766d56b5e344f9cf713d8..f8ce3f90f7785b7ffc5b1000a9d138b32b56d140 100644 (file)
--- a/src/dom/js/jsatom.h
+++ b/src/dom/js/jsatom.h
#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 */
};
};
#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))
jsatomid number; /* one beyond greatest atom number */
jsatomid liveAtoms; /* number of live atoms after last GC */
+ /* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */
+ JSAtom *emptyAtom;
+
/* Type names and value literals. */
JSAtom *typeAtoms[JSTYPE_LIMIT];
JSAtom *booleanAtoms[2];
JSAtom *ErrorAtom;
JSAtom *FunctionAtom;
JSAtom *MathAtom;
+ JSAtom *NamespaceAtom;
JSAtom *NumberAtom;
JSAtom *ObjectAtom;
+ JSAtom *QNameAtom;
JSAtom *RegExpAtom;
JSAtom *ScriptAtom;
JSAtom *StringAtom;
+ JSAtom *XMLAtom;
+ JSAtom *FileAtom;
JSAtom *anonymousAtom;
JSAtom *argumentsAtom;
JSAtom *arityAtom;
JSAtom *classPrototypeAtom;
JSAtom *constructorAtom;
JSAtom *countAtom;
+ JSAtom *eachAtom;
+ JSAtom *etagoAtom;
JSAtom *evalAtom;
JSAtom *getAtom;
JSAtom *getterAtom;
JSAtom *inputAtom;
JSAtom *lengthAtom;
JSAtom *nameAtom;
+ JSAtom *namespaceAtom;
JSAtom *noSuchMethodAtom;
JSAtom *parentAtom;
JSAtom *protoAtom;
+ JSAtom *ptagcAtom;
+ JSAtom *qualifierAtom;
JSAtom *setAtom;
JSAtom *setterAtom;
+ JSAtom *spaceAtom;
+ JSAtom *stagoAtom;
+ JSAtom *starAtom;
+ JSAtom *starQualifierAtom;
+ JSAtom *tagcAtom;
JSAtom *toLocaleStringAtom;
JSAtom *toSourceAtom;
JSAtom *toStringAtom;
JSAtom *valueOfAtom;
+ JSAtom *xmlAtom;
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
struct {
+ JSAtom *AnyNameAtom;
+ JSAtom *AttributeNameAtom;
JSAtom *EvalErrorAtom;
JSAtom *InfinityAtom;
JSAtom *InternalErrorAtom;
JSAtom *SyntaxErrorAtom;
JSAtom *TypeErrorAtom;
JSAtom *URIErrorAtom;
+ JSAtom *XMLListAtom;
JSAtom *decodeURIAtom;
JSAtom *decodeURIComponentAtom;
JSAtom *defineGetterAtom;
JSAtom *encodeURIAtom;
JSAtom *encodeURIComponentAtom;
JSAtom *escapeAtom;
+ JSAtom *functionNamespaceURIAtom;
JSAtom *hasOwnPropertyAtom;
JSAtom *isFiniteAtom;
JSAtom *isNaNAtom;
JSAtom *isPrototypeOfAtom;
+ JSAtom *isXMLNameAtom;
JSAtom *lookupGetterAtom;
JSAtom *lookupSetterAtom;
JSAtom *parseFloatAtom;
extern const char js_Date_str[];
extern const char js_Function_str[];
extern const char js_Math_str[];
+extern const char js_Namespace_str[];
extern const char js_Number_str[];
extern const char js_Object_str[];
+extern const char js_QName_str[];
extern const char js_RegExp_str[];
extern const char js_Script_str[];
extern const char js_String_str[];
+extern const char js_XML_str[];
+extern const char js_File_str[];
extern const char js_anonymous_str[];
extern const char js_arguments_str[];
extern const char js_arity_str[];
extern const char js_class_prototype_str[];
extern const char js_constructor_str[];
extern const char js_count_str[];
+extern const char js_etago_str[];
+extern const char js_each_str[];
extern const char js_eval_str[];
extern const char js_getter_str[];
extern const char js_get_str[];
extern const char js_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[];
diff --git a/src/dom/js/jsbool.c b/src/dom/js/jsbool.c
index 75d4ee05af0185cb18e368d1edd001a2c710b14e..33d5c507eed1eb4f1cbec3ebc5fe72cbe59d1b27 100644 (file)
--- a/src/dom/js/jsbool.c
+++ b/src/dom/js/jsbool.c
#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,
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;
}
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;
}
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;
}
#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)
{
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;
{
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;
}
{
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;
}
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;
diff --git a/src/dom/js/jsbool.h b/src/dom/js/jsbool.h
index c07910f59c04a63607af0253cd61f204a432b4c3..770b94c6ded71ab66442bdb44cbfb0870392ab5a 100644 (file)
--- a/src/dom/js/jsbool.h
+++ b/src/dom/js/jsbool.h
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);
diff --git a/src/dom/js/jsclist.h b/src/dom/js/jsclist.h
index 2eafe8e403b0765e21e514233d4265af0830f81a..604ec0ec95637af2ead25d1124ced0c62d3d934f 100644 (file)
--- a/src/dom/js/jsclist.h
+++ b/src/dom/js/jsclist.h
/*
** 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"
/*
** 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
/*
** 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
/*
** 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) \
diff --git a/src/dom/js/jscntxt.c b/src/dom/js/jscntxt.c
index de254ca9cfca5ab91e70e7e3700cf9871e4b9047..43041f97b3ab5fa4a94f37c7435e1f75fe430608 100644 (file)
--- a/src/dom/js/jscntxt.c
+++ b/src/dom/js/jscntxt.c
#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)
{
* 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) {
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);
{
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)
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;
}
/* 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
* 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;
}
lrs->rootCount = n + 1;
lrc->roots[m] = v;
- return (int) m;
+ return (int) n;
}
void
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
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;
}
*/
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;
/*
*/
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];
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));
* 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;
}
diff --git a/src/dom/js/jscntxt.h b/src/dom/js/jscntxt.h
index 630d6a63f1e39b4fbb13c0495cdac0534a7bd322..bf49c8b8e720c924dd58913576c5b531a63b7c78 100644 (file)
--- a/src/dom/js/jscntxt.h
+++ b/src/dom/js/jscntxt.h
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsregexp.h"
+#include "jsutil.h"
JS_BEGIN_EXTERN_C
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
/* 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;
/* Script filename table. */
struct JSHashTable *scriptFilenameTable;
+ JSCList scriptFilenamePrefixes;
#ifdef JS_THREADSAFE
PRLock *scriptFilenameTableLock;
#endif
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;
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)
};
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;
jsuword stackLimit;
/* Runtime version control identifier and equality operators. */
- JSVersion version;
+ uint16 version;
jsbytecode jsop_eq;
jsbytecode jsop_ne;
/* 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;
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;
/* 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);
diff --git a/src/dom/js/jsconfig.h b/src/dom/js/jsconfig.h
index 44a64d87027e7c98585f70bb3ac095a97053c3a8..5902499f90e85182cc55b96a6bbc41644ebe38e7 100644 (file)
--- a/src/dom/js/jsconfig.h
+++ b/src/dom/js/jsconfig.h
* 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
--- a/src/dom/js/jsconfig.mk
+++ /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:
diff --git a/src/dom/js/jscpucfg.c b/src/dom/js/jscpucfg.c
index aa6c04c4d5548c94cdbd9c2c3829a33409f2d4bb..e02f33615d51464c4e773cd056f259246fb02703 100644 (file)
--- a/src/dom/js/jscpucfg.c
+++ b/src/dom/js/jscpucfg.c
#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 {
struct align_fakelonglong {
char c;
struct {
- long hi, lo;
+ long hi, lo;
} a;
};
struct align_float {
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;
}
bpb = 8;
}
-static int StackGrowthDirection(int *dummy1addr)
+static int NS_NEVER_INLINE StackGrowthDirection(int *dummy1addr)
{
int dummy2;
#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 */
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 {
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 */
diff --git a/src/dom/js/jscpucfg.h b/src/dom/js/jscpucfg.h
index 897ee577cfe9b0f2ec454b8db4b9b892c6e31903..7b8b2add45b4aa9ed72feea926a3c72bae09dc8d 100644 (file)
--- a/src/dom/js/jscpucfg.h
+++ b/src/dom/js/jscpucfg.h
#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
diff --git a/src/dom/js/jsdate.c b/src/dom/js/jsdate.c
index 4d85b1ef73f16d0c5e3acd718be020e602a080a8..a76502c38e0797c08ad4c1f4a21221bcd5b722ac 100644 (file)
--- a/src/dom/js/jsdate.c
+++ b/src/dom/js/jsdate.c
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
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;
}
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;
}
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;
/* 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);
{
intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
if (result < 0)
- result += (intN)HoursPerDay;
+ result += (intN)HoursPerDay;
return result;
}
{
intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
if (result < 0)
- result += (intN)MinutesPerHour;
+ result += (intN)MinutesPerHour;
return result;
}
{
intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
if (result < 0)
- result += (intN)SecondsPerMinute;
+ result += (intN)SecondsPerMinute;
return result;
}
{
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
/* 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;
/* 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;
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);
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
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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;
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
* 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);
/* fprintf(stderr, "%f\n", result); */
if (local)
- result = UTC(result);
+ result = UTC(result);
/* fprintf(stderr, "%f\n", result); */
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 */
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);
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;
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));
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;
}
/* 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;
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.
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] == '/' &&
}
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
*/
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
*/
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);
}
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;
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;
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
/* 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);
}
{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
{
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;
}
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;
}
/* 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"))
/* 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;
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;
/* 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));
}
jsdouble *date = date_getProlog(cx, obj, NULL);
if (!date || JSDOUBLE_IS_NaN(*date))
- return 0;
+ return 0;
return (int) MonthFromTime(LocalTime(*date));
}
jsdouble *date = date_getProlog(cx, obj, NULL);
if (!date || JSDOUBLE_IS_NaN(*date))
- return 0;
+ return 0;
return (int) DateFromTime(LocalTime(*date));
}
jsdouble *date = date_getProlog(cx, obj, NULL);
if (!date || JSDOUBLE_IS_NaN(*date))
- return 0;
+ return 0;
return (int) HourFromTime(LocalTime(*date));
}
jsdouble *date = date_getProlog(cx, obj, NULL);
if (!date || JSDOUBLE_IS_NaN(*date))
- return 0;
+ return 0;
return (int) MinFromTime(LocalTime(*date));
}
jsdouble *date = date_getProlog(cx, obj, NULL);
if (!date || JSDOUBLE_IS_NaN(*date))
- return 0;
+ return 0;
return (int) SecFromTime(*date);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
diff --git a/src/dom/js/jsdate.h b/src/dom/js/jsdate.h
index 790b4daf64f8f35b764422416b369027861b1b0e..343314fab3f9d6e6469369c8a78a3acc4f7743ac 100644 (file)
--- a/src/dom/js/jsdate.h
+++ b/src/dom/js/jsdate.h
*/
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
diff --git a/src/dom/js/jsdbgapi.c b/src/dom/js/jsdbgapi.c
index 8713a86b99fd03cbaa48c0978dd1036aa5cacd80..cddbd480865bfe3c8ad78784a21078155b8ada42 100644 (file)
--- a/src/dom/js/jsdbgapi.c
+++ b/src/dom/js/jsdbgapi.c
}
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);
}
}
JSRuntime *rt;
JSWatchPoint *wp;
JSScopeProperty *sprop;
- jsval userid;
+ jsval propid, userid;
JSScope *scope;
JSBool ok;
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,
* 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)
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);
}
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),
}
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))
/* 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))
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;
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;
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;
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)
{
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;
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 *)
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)
{
JS_PUBLIC_API(JSVersion)
JS_GetScriptVersion(JSContext *cx, JSScript *script)
{
- return script->version;
+ return script->version & JSVERSION_MASK;
}
/***************************************************************************/
const char *filename, uintN lineno,
jsval *rval)
{
- uint32 flags;
+ uint32 flags, options;
JSScript *script;
JSBool ok;
*/
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;
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,
return nbytes;
}
+
+JS_PUBLIC_API(uint32)
+JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
+{
+ if (!fp)
+ fp = cx->fp;
+ while (fp) {
+ if (fp->script) {
+ return JS_GetScriptFilenameFlags(fp->script);
+ }
+ fp = fp->down;
+ }
+ return 0;
+ }
+
+JS_PUBLIC_API(uint32)
+JS_GetScriptFilenameFlags(JSScript *script)
+{
+ JS_ASSERT(script);
+ if (!script->filename)
+ return JSFILENAME_NULL;
+ return js_GetScriptFilenameFlags(script->filename);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
+{
+ if (!js_SaveScriptFilenameRT(rt, prefix, flags))
+ return JS_FALSE;
+ return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_IsSystemObject(JSContext *cx, JSObject *obj)
+{
+ return (*js_GetGCThingFlags(obj) & GCF_SYSTEM) != 0;
+}
+
+JS_PUBLIC_API(void)
+JS_FlagSystemObject(JSContext *cx, JSObject *obj)
+{
+ uint8 *flagp;
+
+ flagp = js_GetGCThingFlags(obj);
+ *flagp |= GCF_SYSTEM;
+}
diff --git a/src/dom/js/jsdbgapi.h b/src/dom/js/jsdbgapi.h
index 90215a275de21fd60481ad94da621967cb8b6c54..d1b13d9d4f3d07f5cfe9286478bcdbff1f136ac9 100644 (file)
--- a/src/dom/js/jsdbgapi.h
+++ b/src/dom/js/jsdbgapi.h
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);
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);
* 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);
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);
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
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 *)
extern JS_PUBLIC_API(void)
JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
- void *callerdata);
+ void *callerdata);
/************************************************************************/
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);
/************************************************************************/
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);
extern JS_PUBLIC_API(size_t)
JS_GetScriptTotalSize(JSContext *cx, JSScript *script);
+/*
+ * Get the top-most running script on cx starting from fp, or from the top of
+ * cx's frame stack if fp is null, and return its script filename flags. If
+ * the script has a null filename member, return JSFILENAME_NULL.
+ */
+extern JS_PUBLIC_API(uint32)
+JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp);
+
+/*
+ * Get the script filename flags for the script. If the script
+ * doesn't have a filename, return JSFILENAME_NULL.
+ */
+extern JS_PUBLIC_API(uint32)
+JS_GetScriptFilenameFlags(JSScript *script);
+
+/*
+ * Associate flags with a script filename prefix in rt, so that any subsequent
+ * script compilation will inherit those flags if the script's filename is the
+ * same as prefix, or if prefix is a substring of the script's filename.
+ *
+ * The API defines only one flag bit, JSFILENAME_SYSTEM, leaving the remaining
+ * 31 bits up to the API client to define. The union of all 32 bits must not
+ * be a legal combination, however, in order to preserve JSFILENAME_NULL as a
+ * unique value. API clients may depend on JSFILENAME_SYSTEM being a set bit
+ * in JSFILENAME_NULL -- a script with a null filename member is presumed to
+ * be a "system" script.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags);
+
+#define JSFILENAME_NULL 0xffffffff /* null script filename */
+#define JSFILENAME_SYSTEM 0x00000001 /* "system" script, see below */
+
+/*
+ * Return true if obj is a "system" object, that is, one flagged by a prior
+ * call to JS_FlagSystemObject(cx, obj). What "system" means is up to the API
+ * client, but it can be used to coordinate access control policies based on
+ * script filenames and their prefixes, using JS_FlagScriptFilenamePrefix and
+ * JS_GetTopScriptFilenameFlags.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_IsSystemObject(JSContext *cx, JSObject *obj);
+
+/*
+ * Flag obj as a "system" object. The API client can flag system objects to
+ * optimize access control checks. The engine stores but does not interpret
+ * the per-object flag set by this call.
+ */
+extern JS_PUBLIC_API(void)
+JS_FlagSystemObject(JSContext *cx, JSObject *obj);
+
JS_END_EXTERN_C
#endif /* jsdbgapi_h___ */
diff --git a/src/dom/js/jsdhash.c b/src/dom/js/jsdhash.c
index abcc36d0516911f701fa42b45bb051d1f8e9161a..cd3006685ad6a5c4f9b0943661533f31e181acc8 100644 (file)
--- a/src/dom/js/jsdhash.c
+++ b/src/dom/js/jsdhash.c
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)
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;
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;
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;
}
diff --git a/src/dom/js/jsdhash.h b/src/dom/js/jsdhash.h
index 68f593b1b1e963b56149e4c39f0b7f27c7a530ef..6beecadd120cd7e65f59fefb219f37fe0a797258 100644 (file)
--- a/src/dom/js/jsdhash.h
+++ b/src/dom/js/jsdhash.h
* 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);
diff --git a/src/dom/js/jsdtoa.c b/src/dom/js/jsdtoa.c
index 9f729fa8ab3f6d9f05b71210662a0fe61dac3f13..ff6731bfaf3e389f7a6cbc3bf2104b2a79365f82 100644 (file)
--- a/src/dom/js/jsdtoa.c
+++ b/src/dom/js/jsdtoa.c
#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__
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
{
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)
*err = 0;
- bb = bd = bs = delta = NULL;
+ bb = bd = bs = delta = NULL;
sign = nz0 = nz = 0;
rv = 0.;
/* 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,
}
return JS_TRUE;
}
-
+
b = NULL; /* initialize for abort protection */
S = NULL;
mlo = mhi = NULL;
-
+
if (!d) {
no_digits:
*decpt = 1;
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
}
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) {
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);
/* 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);
*pInt++ = *q;
*q-- = ch;
}
-
+
df = d - di;
if (df != 0.0) {
/* We have a fraction. */
Bigint *b, *s, *mlo, *mhi;
b = s = mlo = mhi = NULL;
-
+
*p++ = '.';
b = d2b(df, &e, &bbits);
if (!b) {
}
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)
diff --git a/src/dom/js/jsemit.c b/src/dom/js/jsemit.c
index ece00fae1cbd226462e00f965cb843596361d2cf..c7e32f2007815c931920aea30cd58882b6fb7ddb 100644 (file)
--- a/src/dom/js/jsemit.c
+++ b/src/dom/js/jsemit.c
/* -*- 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
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)
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
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)
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;
#endif /* JS_HAS_SWITCH_STATEMENT */
}
+ JS_ASSERT(len > 0);
pc += len;
}
}
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;
}
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
}
}
}
+ cg->main.lastNoteOffset += growth;
/*
* Fix try/catch notes (O(numTryNotes * log2(numSpanDeps)), but it's
} 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);
}
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;
* 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
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;
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);
}
/*
- * 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
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);
}
/*
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.
* 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) {
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 &&
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;
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;
}
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);
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;
}
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 &&
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;
}
}
{
jsint ival;
jsatomid atomIndex;
+ ptrdiff_t off;
+ jsbytecode *pc;
JSAtom *atom;
JSAtomListElement *ale;
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
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) {
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;
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;
}
}
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;
JSAtom *atom;
JSAtomListElement *ale;
jsatomid atomIndex;
- intN noteIndex;
+ ptrdiff_t noteIndex;
JSSrcNoteType noteType;
jsbytecode *pc;
JSOp op;
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);
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));
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);
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;
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;
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;
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
* 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;
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;
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)
/* Quell GCC overwarnings. */
end = catchStart = finallyCatch = catchJump = -1;
-/* Emit JSOP_GOTO that points to the first op after the catch/finally blocks */
-#define EMIT_CATCH_GOTO(cx, cg, jmp) \
- EMIT_BACKPATCH_OP(cx, cg, stmtInfo.catchJump, JSOP_BACKPATCH, jmp)
-
-/* Emit JSOP_GOSUB that points to the finally block. */
-#define EMIT_FINALLY_GOSUB(cx, cg, jmp) \
- EMIT_BACKPATCH_OP(cx, cg, stmtInfo.gosub, JSOP_BACKPATCH_PUSH, jmp)
-
/*
* Push stmtInfo to track jumps-over-catches and gosubs-to-finally
* for later fixup.
* When a finally block is `active' (STMT_FINALLY on the treeContext),
* non-local jumps (including jumps-over-catches) result in a GOSUB
* being written into the bytecode stream and fixed-up later (c.f.
- * EMIT_BACKPATCH_OP and BackPatch).
+ * EmitBackPatchOp and BackPatch).
*/
js_PushStatement(&cg->treeContext, &stmtInfo,
pn->pn_kid3 ? STMT_FINALLY : STMT_BLOCK,
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;
}
/* 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;
*
* 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.
*/
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);
}
} 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;
}
/* 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 */
}
/*
- * 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
* 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);
}
/*
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. */
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) {
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);
}
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))
}
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)) {
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);
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
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;
}
/* 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:
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;
return JS_FALSE;
}
} else {
+#if JS_HAS_XML_SUPPORT
+ case TOK_DBLCOLON:
+ if (pn->pn_arity == PN_NAME) {
+ if (!js_EmitTree(cx, cg, pn->pn_expr))
+ return JS_FALSE;
+ if (!EmitAtomOp(cx, pn, pn->pn_op, cg))
+ return JS_FALSE;
+ break;
+ }
+#endif
/* Binary operators that evaluate both operands unconditionally. */
if (!js_EmitTree(cx, cg, pn->pn_left))
return JS_FALSE;
#if JS_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;
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;
: 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;
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:
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
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
* 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.
*/
}
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;
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;
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) {
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
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 */
}
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:
/*
ok = EmitNumberOp(cx, pn->pn_dval, cg);
break;
+#if JS_HAS_XML_SUPPORT
+ case TOK_ANYNAME:
+#endif
case TOK_PRIMARY:
if (js_Emit1(cx, cg, pn->pn_op) < 0)
return JS_FALSE;
break;
#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);
}
return sn;
}
-uintN
+JS_FRIEND_API(uintN)
js_SrcNoteLength(jssrcnote *sn)
{
uintN arity;
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++) {
diff --git a/src/dom/js/jsemit.h b/src/dom/js/jsemit.h
index 3c8c9c6ae18aad2cf331261d1dc10b888550478c..6ec4600b4d972035a53766839aec61fb5cddce54 100644 (file)
--- a/src/dom/js/jsemit.h
+++ b/src/dom/js/jsemit.h
#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, \
#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 */
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 */
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 */
diff --git a/src/dom/js/jsexn.c b/src/dom/js/jsexn.c
index 6d3a182db1876ebc8a1f54d78d538c1fa247e28b..c637a5630123967b1beea9eb9277b5a6add3a762 100644 (file)
--- a/src/dom/js/jsexn.c
+++ b/src/dom/js/jsexn.c
/* -*- 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
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;
}
/*
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
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);
+ }
}
}
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_) { \
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_) { \
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;
#undef APPEND_CHAR_TO_STACK
#undef APPEND_STRING_TO_STACK
+#undef STACK_LENGTH_LIMIT
done:
if (checkAccess) {
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;
* 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;
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}
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;
: 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;
/* 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
{
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;
}
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;
/*
* 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
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 {
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 */
diff --git a/src/dom/js/jsfile.c b/src/dom/js/jsfile.c
index ef5e93b29a27ef86d5ced5dd5b22fd92dab648cc..2237dbd4710bc5c64a4e51f904ea58f0cc9dc1e5 100644 (file)
--- a/src/dom/js/jsfile.c
+++ b/src/dom/js/jsfile.c
/* -*- 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 {
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
{
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; \
}
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... */
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 */
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)
# 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;
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;
}
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);
}
/* 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, "");
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);
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') {
}
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;
}
#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;
}
/*
char *options = JS_strdup(cx, oldoptions);
int32 found = 0;
- current = options;
+ current = options;
for (;;) {
comma = strchr(current, ',');
if (comma) *comma = '\0';
{
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
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;
}
}
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];
}
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);
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) {
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;
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);
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) {
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;
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;
}
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
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
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
{
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);
+ }
}
/*
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);
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 */
{
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){
*/
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 ------------------------- */
{ "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}
};
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);
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);
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;
}
return JS_TRUE;
out:
- *vp = JSVAL_VOID;
- return JS_FALSE;
+ return JS_FALSE;
}
/*
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;
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));
diff --git a/src/dom/js/jsfile.h b/src/dom/js/jsfile.h
index 47a8692d8f81be369bef3eca326a82430156983e..741c5bdd02308c0cd84006b81bf0d42ecab52586 100644 (file)
--- a/src/dom/js/jsfile.h
+++ b/src/dom/js/jsfile.h
#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);
diff --git a/src/dom/js/jsfile.msg b/src/dom/js/jsfile.msg
index f03c51d42d9d5f8d5b961abedd593548b9ec5afd..137b35d874058fe08d0721f6367f6dafe9cfd32e 100644 (file)
--- a/src/dom/js/jsfile.msg
+++ b/src/dom/js/jsfile.msg
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")
diff --git a/src/dom/js/jsfun.c b/src/dom/js/jsfun.c
index bbb1e1b61324aa2596f681ca2c4704a9b0aefc5c..68372e1296e4fcab57e0789694afb0846aaa4310 100644 (file)
--- a/src/dom/js/jsfun.c
+++ b/src/dom/js/jsfun.c
/* -*- 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
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);
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)
{
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) {
(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 {
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;
}
*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);
{
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)
(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));
}
* 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).
break;
default:
- if ((uintN)slot < MAXARGS(fp) && !MarkArgDeleted(cx, fp, slot))
+ if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot))
return JS_FALSE;
break;
}
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;
}
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;
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)) {
}
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;
JSStackFrame *fp;
JSObject *pobj;
JSProperty *prop;
- uintN slot, nargs;
+ uintN slot, argc;
fp = (JSStackFrame *)
JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
* 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);
}
* 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);
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);
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);
}
JSObject *obj2;
JSProperty *prop;
JSScopeProperty *sprop;
- jsid propid;
JSPropertyOp getter, setter;
uintN attrs, slot, nslots, spflags;
jsval *vp, value;
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;
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;
*objp = obj;
}
}
+
return JS_TRUE;
}
#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}
};
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));
#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:
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)
* 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;
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
JSContext *cx;
JSFunction *fun;
JSString *atomstr;
+ JSTempValueRooter tvr;
uint32 flagsword; /* originally only flags was JS_XDRUint8'd */
char *propname;
JSScopeProperty *sprop;
JSAtom *atom;
uintN i, n, dupflag;
uint32 type;
+ JSBool ok;
#ifdef DEBUG
uintN nvars = 0, nargs = 0;
#endif
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 */
n * sizeof(JSScopeProperty *));
if (!spvec) {
JS_ReportOutOfMemory(cx);
- return JS_FALSE;
+ goto bad;
}
}
scope = OBJ_SCOPE(fun->object);
: 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)
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);
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;
/* 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 */
JSString *str;
if (!OBJ_GET_PROPERTY(cx, obj,
- (jsid)cx->runtime->atomState.classPrototypeAtom,
+ ATOM_TO_JSID(cx->runtime->atomState
+ .classPrototypeAtom),
&pval)) {
return JS_FALSE;
}
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;
* 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,
&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))
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;
}
{"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}
};
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;
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;
#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);
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
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;
/*
* 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) {
*/
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++;
/*
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.
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;
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)
{
diff --git a/src/dom/js/jsfun.h b/src/dom/js/jsfun.h
index eb79161a90f58710a78e2440cd3659dfab0a6033..25aa10320a5e58889ebacbef3b0553eebe48bdbc 100644 (file)
--- a/src/dom/js/jsfun.h
+++ b/src/dom/js/jsfun.h
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 */
* 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
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);
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
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);
diff --git a/src/dom/js/jsgc.c b/src/dom/js/jsgc.c
index 754f4ae6d1fb4609b99ee56b54d9df1ae5b52904..2383240c7edbe892455b467e49019f6b76068175 100644 (file)
--- a/src/dom/js/jsgc.c
+++ b/src/dom/js/jsgc.c
#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.
#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;
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;
{
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,
JSBool
js_InitGC(JSRuntime *rt, uint32 maxbytes)
{
+ uintN i;
+
JS_ASSERT(sizeof(JSGCThing) == sizeof(JSGCPageInfo));
JS_ASSERT(sizeof(JSGCThing) >= sizeof(JSObject));
JS_ASSERT(sizeof(JSGCThing) >= sizeof(JSString));
JS_ASSERT(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) {
JS_DHashTableDestroy(rt->gcLocksHash);
rt->gcLocksHash = NULL;
}
- rt->gcFreeList = NULL;
}
JSBool
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);
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
* 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);
}
/*
* 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
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,
*/
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;
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;
}
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;
#ifdef GC_MARK_DEBUG
#include <stdio.h>
-#include <stdlib.h>
#include "jsprf.h"
JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
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)
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;
#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;
#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;
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) {
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;
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))
return;
}
METER(rt->gcStats.poke++);
+ rt->gcPoke = JS_FALSE;
#ifdef JS_THREADSAFE
/* Bump gcLevel and return rather than nest on this thread. */
/* 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);
}
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) {
/*
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))
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);
}
/* 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);
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);
/*
* 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. */
diff --git a/src/dom/js/jsgc.h b/src/dom/js/jsgc.h
index a4813d16d57082d3173b9b54c8f8eba079682f25..efc13194ee1e9521e0704652c3269410fdf4f9e4 100644 (file)
--- a/src/dom/js/jsgc.h
+++ b/src/dom/js/jsgc.h
#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. */
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);
extern JSBool
js_UnlockGCThingRT(JSRuntime *rt, void *thing);
-extern JSBool
+extern JSBool
js_IsAboutToBeFinalized(JSContext *cx, void *thing);
extern void
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)
* 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
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 */
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___ */
diff --git a/src/dom/js/jshash.c b/src/dom/js/jshash.c
index 954368450196d3ea03136e807c08903cd1fba635..0f22b5e39c767a5bb38746f2a616e7e1a85db1dc 100644 (file)
--- a/src/dom/js/jshash.c
+++ b/src/dom/js/jshash.c
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);
if (!ht->buckets) {
ht->buckets = oldbuckets;
return NULL;
- }
+ }
memset(ht->buckets, 0, nb);
#ifdef HASHMETER
ht->ngrows++;
/* 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;
diff --git a/src/dom/js/jsinterp.c b/src/dom/js/jsinterp.c
index 6881e07dd22f059de36be9376090717c70e93515..096610cf36c1cf4110bcefbcf4e926250a069183 100644 (file)
--- a/src/dom/js/jsinterp.c
+++ b/src/dom/js/jsinterp.c
/* -*- 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 \
&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 = {
#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); \
} \
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)) { \
sp += 2;
}
+ /*
+ * Store JSVAL_NULL using memset, to let compilers optimize as they see
+ * fit, in case a caller allocates and pushes GC-things one by one, which
+ * could nest a last-ditch GC that will scan this segment.
+ */
+ memset(sp, 0, nslots * sizeof(jsval));
return sp;
}
JS_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)
{
JSBool
js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
- return SetFunctionSlot(cx, obj, js_SetArgument, id, *vp);
+ return JS_TRUE;
}
JSBool
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);
*/
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;
JSNative native;
JSFunction *fun;
JSScript *script;
- uintN minargs, nvars;
- intN nslots, nalloc, surplus;
+ uintN nslots, nvars, nalloc, surplus;
JSInterpreterHook hook;
void *hookData;
*/
if (JSVAL_IS_PRIMITIVE(v)) {
#if JS_HAS_NO_SUCH_METHOD
+ jsid id;
jsbytecode *pc;
jsatomid atomIndex;
JSAtom *atom;
* 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))
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);
* 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)
}
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;
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. */
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;
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;
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;
/* 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)
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;
}
/* 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);
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;
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);
frame.sharpDepth = 0;
frame.flags = flags;
frame.dormantNext = NULL;
+ frame.xmlNamespace = NULL;
/*
* Here we wrap the call to js_Interpret with code to (conditionally)
* 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) {
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)
: 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,
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
#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;
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;
#endif
#if JS_HAS_GETTER_SETTER
JSPropertyOp getter, setter;
+#endif
+#if JS_HAS_XML_SUPPORT
+ JSBool foreach = JS_FALSE;
#endif
int stackDummy;
/*
* 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
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
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;
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));
break;
case JSOP_GROUP:
- obj = NULL;
break;
case JSOP_PUSH:
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;
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:
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);
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. */
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);
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);
*/
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
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;
/*
*/
*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);
}
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? */
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.
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) {
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;
sp += i + 1;
PUSH_OPND(rval);
break;
+ }
case JSOP_DUP:
JS_ASSERT(sp > fp->spbase);
#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); \
#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; \
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); \
} \
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));
goto out;
sp--;
STORE_OPND(-1, rval);
+ obj = NULL;
break;
#define INTEGER_OP(OP, EXTRA_CODE) \
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); \
} 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); \
} 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); \
} 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; \
} \
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) { \
} 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); \
} \
} \
} \
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);
break;
case JSOP_CASEX:
- NEW_EQUALITY_OP(==, JS_FALSE);
+ NEW_EQUALITY_OP(==);
(void) POP();
if (cond) {
len = GET_JUMPX_OFFSET(pc);
case JSOP_ADD:
rval = FETCH_OPND(-1);
lval = FETCH_OPND(-2);
- VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, <mp);
- 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;
#if JS_HAS_INITIALIZERS
do_new:
#endif
+ SAVE_SP(fp);
vp = sp - (2 + argc);
JS_ASSERT(vp >= fp->spbase);
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;
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);
/* 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);
/* 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;
}
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);
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;
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:
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);
OBJ_DROP_PROPERTY(cx, obj2, prop);
lval = OBJECT_TO_JSVAL(obj);
+ i = 0;
goto do_incop;
case JSOP_INCPROP:
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);
/*
* 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 \
ok = js_NewNumberValue(cx, d, &rtmp); \
if (!ok) \
goto out; \
+ *vp = rtmp; \
} \
(cs->format & JOF_INC) ? d++ : d--; \
ok = js_NewNumberValue(cx, d, &rval); \
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;
#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;
/* 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:
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);
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;
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. */
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);
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;
* 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);
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.
PUSH_OPND(rval);
obj = NULL;
- break;
}
+ END_LITOPX_CASE
case JSOP_ZERO:
PUSH_OPND(JSVAL_ZERO);
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;
* 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;
* 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;
#if JS_HAS_EXPORT_IMPORT
case JSOP_EXPORTALL:
+ SAVE_SP(fp);
obj = fp->varobj;
ida = JS_Enumerate(cx, obj);
if (!ida) {
}
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;
}
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;
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;
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)
#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)
* 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)
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;
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;
* 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)) {
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
* 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.
*
* 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
* 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
* 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) {
/*
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
* 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;
}
}
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;
}
}
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));
* 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;
* 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],
*/
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,
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;
* 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
* 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);
* 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
*/
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,
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
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
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));
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,
if (!ok)
goto out;
+ obj = NULL;
sp += i;
if (cs->ndefs)
STORE_OPND(-1, rval);
/* 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;
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;
#if JS_HAS_SHARP_VARS
case JSOP_DEFSHARP:
+ SAVE_SP(fp);
obj = fp->sharpArray;
if (!obj) {
obj = js_NewArrayObject(cx, 0, NULL);
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];
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;
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));
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;
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:
/* 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) {
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;
}
#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);
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) {
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
/*
* 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;
diff --git a/src/dom/js/jsinterp.h b/src/dom/js/jsinterp.h
index 81f16d76022f15d570084f2dfff25397cf6f4cc2..edf70f86f3ec1c8b1cc21f0d196ef04f3938d761 100644 (file)
--- a/src/dom/js/jsinterp.h
+++ b/src/dom/js/jsinterp.h
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 {
#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
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);
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
diff --git a/src/dom/js/jslibmath.h b/src/dom/js/jslibmath.h
index 7cbcf767abe6797e72e5831db8fdf79e15c3cb6b..544d8f800b561e595aa98028f092531b0acd036b 100644 (file)
--- a/src/dom/js/jslibmath.h
+++ b/src/dom/js/jslibmath.h
#define __P(p) ()
#endif
-#if defined _WIN32 || defined SUNOS4
+#if (defined _WIN32 && !defined WINCE) || defined SUNOS4
#define fd_acos acos
#define fd_asin asin
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));
diff --git a/src/dom/js/jslock.c b/src/dom/js/jslock.c
index e0c87b1fcd3943bc89eb3e0e0932af43d53a6deb..968e98b84167c6593ad27683e274b08829726838 100644 (file)
--- a/src/dom/js/jslock.c
+++ b/src/dom/js/jslock.c
* state update.
*/
if (!oldscope)
- return;
+ return;
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, oldscope));
/*
* was actually locked.
*/
if (CX_THREAD_IS_RUNNING_GC(cx))
- return;
+ return;
/*
* Special case in js_LockObj and js_UnlockScope for locking the sealed
diff --git a/src/dom/js/jslock.h b/src/dom/js/jslock.h
index 9ece59c9b9823c074dce1ffa61d73726b6130f04..0ab71927b2d5c19ab99de5000d6b4df2fd8448f8 100644 (file)
--- a/src/dom/js/jslock.h
+++ b/src/dom/js/jslock.h
* 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)
*/
#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)
#define JS_LOCK(P,CX) JS_LOCK0(P,(CX)->thread)
#define JS_UNLOCK(P,CX) JS_UNLOCK0(P,(CX)->thread)
-#ifndef SET_OBJ_INFO
-#define SET_OBJ_INFO(obj,f,l) ((void)0)
-#endif
-#ifndef SET_SCOPE_INFO
-#define SET_SCOPE_INFO(scope,f,l) ((void)0)
-#endif
-
#endif /* jslock_h___ */
diff --git a/src/dom/js/jslocko.asm b/src/dom/js/jslocko.asm
index 2589bb7f929016363167d07a56dd17bfdead5016..95353ba1a0939473def9089eaa0c77b7f86d43c4 100644 (file)
--- a/src/dom/js/jslocko.asm
+++ b/src/dom/js/jslocko.asm
-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
diff --git a/src/dom/js/jslog2.c b/src/dom/js/jslog2.c
index 113c276d0e64d10bc6c68bb48056dde2108bb116..9bfca4dd31c975fff66b8797540363a21c1b4a27 100644 (file)
--- a/src/dom/js/jslog2.c
+++ b/src/dom/js/jslog2.c
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;
}
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;
}
diff --git a/src/dom/js/jslong.c b/src/dom/js/jslong.c
index 76259e502ea1abe5959c9c711195428fe2306c3f..9a4a5b4d789a3f3502795be740b70ea3002090b3 100644 (file)
--- a/src/dom/js/jslong.c
+++ b/src/dom/js/jslong.c
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;
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;
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 */
diff --git a/src/dom/js/jslong.h b/src/dom/js/jslong.h
index bde8bfbbf17d7abcfa7b4b584fabbb4c1e2bff1f..059cf00bb2293e7d0863ffecd023dc2a8e118755 100644 (file)
--- a/src/dom/js/jslong.h
+++ b/src/dom/js/jslong.h
/***********************************************************************
** 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
diff --git a/src/dom/js/jsmath.c b/src/dom/js/jsmath.c
index 9c6fcec0e43abebb668d48c482b86c77cc5cf98f..19005eafa2e26f25f55dc3d363286d0a92ad2154 100644 (file)
--- a/src/dom/js/jsmath.c
+++ b/src/dom/js/jsmath.c
#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[] = {
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);
}
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);
}
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);
}
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);
}
/* Do at most once. */
if (rt->rngInitialized)
- return;
+ return;
rt->rngInitialized = JS_TRUE;
/* rt->rngMultiplier = 0x5DEECE66DL */
#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;
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}
};
js_InitMathClass(JSContext *cx, JSObject *obj)
{
JSObject *Math;
-
+
Math = JS_DefineObject(cx, obj, "Math", &math_class, NULL, 0);
if (!Math)
return NULL;
diff --git a/src/dom/js/jsmath.h b/src/dom/js/jsmath.h
index 7a6b21657bc68aae10d9c359de56c967c0c1f07f..b67dba1deb79e9aabfffdad994c6165af9075330 100644 (file)
--- a/src/dom/js/jsmath.h
+++ b/src/dom/js/jsmath.h
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and 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"),
diff --git a/src/dom/js/jsnum.c b/src/dom/js/jsnum.c
index 9de1d72db72c29c4bbc19d201624d8b7a0114827..8a5596304e3d84c26a975ab82c6d6598c03a8c07 100644 (file)
--- a/src/dom/js/jsnum.c
+++ b/src/dom/js/jsnum.c
@@ -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)
{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));
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));
#if (defined XP_WIN || defined XP_OS2) && \
+ !defined WINCE && \
!defined __MWERKS__ && \
(defined _M_IX86 || \
(defined __GNUC__ && !defined __MINGW32__))
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;
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;
}
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;
{
jsdouble *dp;
- dp = js_NewDouble(cx, d);
+ dp = js_NewDouble(cx, d, 0);
if (!dp)
return JS_FALSE;
*rval = DOUBLE_TO_JSVAL(dp);
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)) {
diff --git a/src/dom/js/jsnum.h b/src/dom/js/jsnum.h
index 28f40e6ecb800a82e0e30b92ff2816310e4ca38a..cd99501e77fc6663a1ec96f04573b906563b9ff7 100644 (file)
--- a/src/dom/js/jsnum.h
+++ b/src/dom/js/jsnum.h
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;
((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
*/
#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
js_FinishRuntimeNumberState(JSContext *cx);
/* Initialize the Number class, returning its prototype object. */
+extern JSClass js_NumberClass;
+
extern JSObject *
js_InitNumberClass(JSContext *cx, JSObject *obj);
/* 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);
diff --git a/src/dom/js/jsobj.c b/src/dom/js/jsobj.c
index 847040c615f7615905d0f6453ca6f6fee40bc19e..03a5980940a96550160b0f7ab5c04684a08bc720 100644 (file)
--- a/src/dom/js/jsobj.c
+++ b/src/dom/js/jsobj.c
/* -*- 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
#define NATIVE_DROP_PROPERTY NULL
#endif
-#ifdef XP_MAC
-#pragma export on
-#endif
-
JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
js_NewObjectMap, js_DestroyObjectMap,
-#if defined JS_THREADSAFE && defined DEBUG
- _js_LookupProperty, js_DefineProperty,
-#else
js_LookupProperty, js_DefineProperty,
-#endif
js_GetProperty, js_SetProperty,
js_GetAttributes, js_SetAttributes,
js_DeleteProperty, js_DefaultValue,
js_GetRequiredSlot, js_SetRequiredSlot
};
-#ifdef XP_MAC
-#pragma export off
-#endif
-
JSClass js_ObjectClass = {
js_Object_str,
0,
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;
}
{
JSObject *pobj;
uint32 slot;
+ jsid propid;
uintN attrs;
if (!JSVAL_IS_OBJECT(*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);
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 *
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;
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];
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
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;
}
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;
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;
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);
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;
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;
}
}
-#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
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;
JSProperty *prop;
uintN attrs;
#endif
- jsval val[2];
+ jsval *val;
JSString *gsop[2];
JSAtom *atom;
JSString *idstr, *valstr, *str;
* 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;
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];
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
*/
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);
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
}
#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);
}
*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 */
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
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,
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;
#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;
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
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];
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;
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);
{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
*/
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
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)
}
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);
#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;
}
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;
}
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) {
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.
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);
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
/* 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;
}
{
JSObjectMap *map;
JSClass *clasp;
- uint32 nslots, i;
+ uint32 nslots;
jsval *newslots;
map = obj->map;
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
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
/* 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); \
} \
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;
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,
* 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);
}
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,
* 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
/*
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
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. */
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)
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)
* 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;
#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
* 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;
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;
}
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);
}
}
}
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);
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;
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;
}
* 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))
* 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)
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))
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
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;
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;
/*
* 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. */
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) {
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
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;
}
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;
}
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;
}
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;
}
js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
{
JSClass *clasp;
+ JSString *str;
clasp = OBJ_GET_CLASS(cx, obj);
if (clasp->hasInstance)
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;
}
}
}
#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
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)
* 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;
}
* 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);
}
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
* 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;
}
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);
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";
js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
{
JSScope *scope;
- uint32 nslots, i;
+ uint32 nslots;
JSClass *clasp;
jsval *newslots;
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. */
diff --git a/src/dom/js/jsobj.h b/src/dom/js/jsobj.h
index 9ac5857e0978b7b821fa35e1c6bd04a6485c11f7..a2400e982316705e8164a3abed9c0965875ddff5 100644 (file)
--- a/src/dom/js/jsobj.h
+++ b/src/dom/js/jsobj.h
/* -*- 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
};
/* Shorthand macros for frequently-made calls. */
-#if defined JS_THREADSAFE && defined DEBUG
-#define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp) \
- (obj)->map->ops->lookupProperty(cx,obj,id,objp,propp,__FILE__,__LINE__)
-#else
#define OBJ_LOOKUP_PROPERTY(cx,obj,id,objp,propp) \
(obj)->map->ops->lookupProperty(cx,obj,id,objp,propp)
-#endif
#define OBJ_DEFINE_PROPERTY(cx,obj,id,value,getter,setter,attrs,propp) \
(obj)->map->ops->defineProperty(cx,obj,id,value,getter,setter,attrs,propp)
#define OBJ_GET_PROPERTY(cx,obj,id,vp) \
? (obj)->map->ops->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,
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;
#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);
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);
extern JSObject *
js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);
+extern JSBool
+js_FindConstructor(JSContext *cx, JSObject *start, const char *name, jsval *vp);
+
extern JSObject *
js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, uintN argc, jsval *argv);
extern void
js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot);
+/*
+ * Native property add and lookup variants that hide id in the hidden atom
+ * subspace, so as to avoid collisions between internal properties such as
+ * formal arguments and local variables in function objects, and externally
+ * set properties with the same ids.
+ */
+extern JSScopeProperty *
+js_AddHiddenProperty(JSContext *cx, JSObject *obj, jsid id,
+ JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
+ uintN attrs, uintN flags, intN shortid);
+
+extern JSBool
+js_LookupHiddenProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp);
+
/*
* Find or create a property named by id in obj's scope, with the given getter
* and setter, slot, attributes, and other members.
*/
extern 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,
* *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);
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);
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);
extern JSBool
js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto,
- uintN attrs);
+ uintN attrs);
extern JSBool
js_ValueToObject(JSContext *cx, jsval v, JSObject **objp);
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);
extern JSBool
js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v);
+extern JSObject *
+js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller);
+
+extern JSBool
+js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj,
+ JSPrincipals *principals, const char *caller);
JS_END_EXTERN_C
#endif /* jsobj_h___ */
diff --git a/src/dom/js/jsopcode.c b/src/dom/js/jsopcode.c
index e751103a0fd4f25b2df4e74dcf504d7d9496d544..80c7eb4dd0bd794352b2cdc236862e2ac7582e62 100644 (file)
--- a/src/dom/js/jsopcode.c
+++ b/src/dom/js/jsopcode.c
/* -*- 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
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[] = {"++", "--"};
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);
#ifdef DEBUG
-JS_FRIEND_API(void)
+JS_FRIEND_API(JSBool)
js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
{
jsbytecode *pc, *end;
PTRDIFF(pc, script->code, jsbytecode),
lines, fp);
if (!len)
- return;
+ return JS_FALSE;
pc += len;
}
+ return JS_TRUE;
}
JS_FRIEND_API(uintN)
uint32 type;
JSAtom *atom;
JSString *str;
- char *cstr;
op = (JSOp)*pc;
if (op >= JSOP_LIMIT) {
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:
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;
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);
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);
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;
}
/* 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);
}
/* 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;
}
/* 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;
} 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,
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;
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);
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))
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");
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)
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
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
(!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; \
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;
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;
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;
}
} 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
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;
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:;
case JSOP_PUSH:
case JSOP_PUSHOBJ:
case JSOP_BINDNAME:
+ do_JSOP_BINDNAME:
todo = Sprint(&ss->sprinter, "");
break;
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;
* 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;
}
break;
#if JS_HAS_EXCEPTIONS
+ case JSOP_THROWING:
+ todo = -2;
+ break;
+
case JSOP_THROW:
sn = js_GetSrcNote(jp->script, pc);
todo = -2;
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);
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));
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)
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) {
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();
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:
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:
/* 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);
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:
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
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);
}
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)) {
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);
}
pc2 += jmplen;
}
- js_HeapSort(table, (size_t) j, sizeof(TableEntry),
+ js_HeapSort(table, (size_t) j, &pivot, sizeof(TableEntry),
CompareOffsets, NULL);
}
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:
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();
break;
case JSOP_IMPORTPROP:
+ do_importprop:
GET_ATOM_QUOTE_AND_FMT("\timport %s[%s]\n", "\timport %s.%s\n",
rval);
lval = POP_STR();
case JSOP_IMPORTELEM:
xval = POP_STR();
op = JSOP_GETELEM;
+ if (js_CodeSpec[lastop].format & JOF_XMLNAME)
+ goto do_importprop;
lval = POP_STR();
js_printf(jp, "\timport %s[%s]\n", lval, xval);
todo = -2;
break;
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();
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,
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
}
}
/*
* 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;
* an expression by parenthesizing.
*/
if (jp->pretty) {
- js_puts(jp, "\n");
js_printf(jp, "\t");
} else {
if (!jp->grouped && (fun->flags & JSFUN_LAMBDA))
js_puts(jp, "(");
if (fun->interpreted && fun->object) {
+ size_t paramsize;
+
/*
* Print the parameters.
*
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)
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, ")");
}
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;
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;
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
}
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;
diff --git a/src/dom/js/jsopcode.h b/src/dom/js/jsopcode.h
index 01a6d46ac7905da0e12887495c1ee27edecc76bc..2a488f6eb66df2f7547c8d2d2ec5bbaa3ee8f2ce 100644 (file)
--- a/src/dom/js/jsopcode.h
+++ b/src/dom/js/jsopcode.h
#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 */
#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))
#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)
*/
#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)
#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. */
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[];
*/
#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 */
/*
*/
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)
--- a/src/dom/js/jsopcode.tbl
+++ b/src/dom/js/jsopcode.tbl
* 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 */
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)
/* 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)
* 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)
/* 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)
* 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)
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)
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)
diff --git a/src/dom/js/jsosdep.h b/src/dom/js/jsosdep.h
index c93eee2f1551649a3fc94319744aad1af3827da2..e9c4a5534b316ca656447de5cf9ae9508a825999 100644 (file)
--- a/src/dom/js/jsosdep.h
+++ b/src/dom/js/jsosdep.h
#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
diff --git a/src/dom/js/jsotypes.h b/src/dom/js/jsotypes.h
index ad8b5203e3059808717d165e6f23347b6fb19a1c..ede1221b8121c2cc18af221b4a772b7742623b37 100644 (file)
--- a/src/dom/js/jsotypes.h
+++ b/src/dom/js/jsotypes.h
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;
#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;
#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
#define PR_CompareStrings PL_CompareStrings
#define PR_CompareValues PL_CompareValues
-#ifdef XP_MAC
-#ifndef TRUE /* Mac standard is lower case true */
- #define TRUE 1
-#endif
-#ifndef FALSE /* Mac standard is lower case false */
- #define FALSE 0
-#endif
-#endif
-
#endif /* !defined(PROTYPES_H) */
diff --git a/src/dom/js/jsparse.c b/src/dom/js/jsparse.c
index 6b3f7600c5e009a7e4b4b4ccc338ebb99a6ac69a..1438f35a21b2acb8c233d4a6ab9be53b7200f0a2 100644 (file)
--- a/src/dom/js/jsparse.c
+++ b/src/dom/js/jsparse.c
* 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 *
#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
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; \
} \
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 *
break;
}
}
+#ifdef METER_PARSENODES
+ if (pn) {
+ parsenodes++;
+ if (parsenodes - recyclednodes > maxparsenodes)
+ maxparsenodes = parsenodes - recyclednodes;
+ }
+#endif
return pn;
}
* Allocate a JSParseNode from cx's temporary arena.
*/
static JSParseNode *
-NewParseNode(JSContext *cx, 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;
}
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;
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;
}
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
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,
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.
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 {
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;
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 {
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;
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);
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;
}
}
cx->fp = fp;
- tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
+ tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS));
return pn;
}
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;
#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;
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)
* 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++;
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)) {
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;
* 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,
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));
}
#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
#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 *
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);
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. */
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"
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;
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)) {
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;
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 */
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;
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);
#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);
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);
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);
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;
}
/* 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) {
}
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;
}
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);
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)
#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);
#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);
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
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 {
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;
}
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'. */
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;
}
/* 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;
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;
*
* 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);
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;
}
* (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;
*/
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;
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;
}
}
case TOK_THROW:
- pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
+ pn = NewParseNode(cx, ts, PN_UNARY, tc);
if (!pn)
return NULL;
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;
}
/* 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))
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;
}
} 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;
}
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))
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;
} 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;
}
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);
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;
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;
#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;
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)
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;
}
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;
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;
}
* 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);
/*
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)
}
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;
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)) {
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,
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) {
/*
* 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:
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++;
}
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 {
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;
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;
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;
}
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;
}
#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)
JSTokenType tt;
JSParseNode *pn, *pn2;
+ CHECK_RECURSION();
+
ts->flags |= TSF_OPERAND;
tt = js_GetToken(cx, ts);
ts->flags &= ~TSF_OPERAND;
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 */
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);
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);
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))
} 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;
}
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);
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);
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;
}
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);
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;
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);
}
}
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;
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;
? 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;
/* 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)) {
}
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;
}
}
#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;
}
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;
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;
#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;
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) {
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;
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;
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;
}
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)
{
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))
}
/* 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;
}
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:;
}
diff --git a/src/dom/js/jsparse.h b/src/dom/js/jsparse.h
index 9ce12b3916c007079c014a603aabcd4bf704df5a..24b27bdc1265f45ed2ff5d468663af86ba502f6e 100644 (file)
--- a/src/dom/js/jsparse.h
+++ b/src/dom/js/jsparse.h
/*
* JS parser definitions.
*/
+#include "jsconfig.h"
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsscan.h"
* 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
* 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,
} 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 */
jsint slot; /* -1 or arg or local var slot */
uintN attrs; /* attributes if local var or const */
} name;
+ struct {
+ JSAtom *atom; /* first atom in pair */
+ JSAtom *atom2; /* second atom in pair or null */
+ } apair;
jsdouble dval; /* aligned numeric literal value */
} pn_u;
JSParseNode *pn_next; /* to align dval and pn_u on RISCs */
+#if JS_HAS_XML_SUPPORT
+ JSTokenStream *pn_ts; /* token stream for XML error reports */
+#endif
};
#define pn_funAtom pn_u.func.funAtom
#define pn_slot pn_u.name.slot
#define pn_attrs pn_u.name.attrs
#define pn_dval pn_u.dval
+#define pn_atom2 pn_u.apair.atom2
/* PN_LIST pn_extra flags. */
#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */
#define PNX_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
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) \
(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) \
extern JSBool
js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc);
+#if JS_HAS_XML_SUPPORT
+JS_FRIEND_API(JSParseNode *)
+js_ParseXMLTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
+ JSBool allowList);
+#endif
+
JS_END_EXTERN_C
#endif /* jsparse_h___ */
diff --git a/src/dom/js/jsprf.c b/src/dom/js/jsprf.c
index 591313ef7c76e02cf29661393d2424a8ed6f1a02..ba7c0f03b4ea8177369e7567c576162785bfed6f 100644 (file)
--- a/src/dom/js/jsprf.c
+++ b/src/dom/js/jsprf.c
#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,
#define TYPE_STRING 8
#define TYPE_DOUBLE 9
#define TYPE_INTSTR 10
+#define TYPE_WSTRING 11
#define TYPE_UNKNOWN 20
#define FLAG_LEFT 0x1
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,
break;
case 's':
- nas[ cn ].type = TYPE_STRING;
+ nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
break;
case 'n':
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;
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;
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
break;
case 'c':
- u.ch = va_arg(ap, int);
if ((flags & FLAG_LEFT) == 0) {
while (width-- > 1) {
rv = (*ss->stuff)(ss, " ", 1);
}
}
}
- 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;
}
#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;
}
diff --git a/src/dom/js/jsprf.h b/src/dom/js/jsprf.h
index e8cc46c0cd1ea8914cf2d303f2e1f9799db629a2..0eb910f279dbc8eb6ed690ba77427dc4edad33f0 100644 (file)
--- a/src/dom/js/jsprf.h
+++ b/src/dom/js/jsprf.h
/*
** API for PR printf like routines. Supports the following formats
-** %d - decimal
-** %u - unsigned decimal
-** %x - unsigned hex
-** %X - unsigned uppercase hex
-** %o - unsigned octal
-** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above
-** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above
-** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above
-** %s - string
-** %c - character
-** %p - pointer (deals with machine dependent pointer size)
-** %f - float
-** %g - float
+** %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>
diff --git a/src/dom/js/jsprvtd.h b/src/dom/js/jsprvtd.h
index f5f1e77f60126e70859438dbaeab387fb2e40d7c..ed12f1bde5b66683d6adabac46a6df8b76a82d68 100644 (file)
--- a/src/dom/js/jsprvtd.h
+++ b/src/dom/js/jsprvtd.h
#include "jspubtd.h"
+/* Internal identifier (jsid) macros. */
+#define JSID_ATOM 0x0
+#define JSID_INT 0x1
+#define JSID_OBJECT 0x2
+#define JSID_TAGMASK 0x3
+#define JSID_TAG(id) ((id) & JSID_TAGMASK)
+#define JSID_SETTAG(id,t) ((id) | (t))
+#define JSID_CLRTAG(id) ((id) & ~(jsid)JSID_TAGMASK)
+
+#define JSID_IS_ATOM(id) (JSID_TAG(id) == JSID_ATOM)
+#define JSID_TO_ATOM(id) ((JSAtom *)(id))
+#define ATOM_TO_JSID(atom) ((jsid)(atom))
+#define ATOM_JSID_TO_JSVAL(id) ATOM_KEY(JSID_TO_ATOM(id))
+
+#define JSID_IS_INT(id) ((id) & JSID_INT)
+#define JSID_TO_INT(id) ((jsint)(id) >> 1)
+#define INT_TO_JSID(i) (((jsint)(i) << 1) | JSID_INT)
+#define INT_JSID_TO_JSVAL(id) (id)
+#define INT_JSVAL_TO_JSID(v) (v)
+
+#define JSID_IS_OBJECT(id) (JSID_TAG(id) == JSID_OBJECT)
+#define JSID_TO_OBJECT(id) ((JSObject *) JSID_CLRTAG(id))
+#define OBJECT_TO_JSID(obj) ((jsid)(obj) | JSID_OBJECT)
+#define OBJECT_JSID_TO_JSVAL(id) OBJECT_TO_JSVAL(JSID_CLRTAG(id))
+#define OBJECT_JSVAL_TO_JSID(v) OBJECT_TO_JSID(JSVAL_TO_OBJECT(v))
+
/* Scalar typedefs. */
typedef uint8 jsbytecode;
typedef uint8 jssrcnote;
typedef 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 {
} 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,
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
diff --git a/src/dom/js/jspubtd.h b/src/dom/js/jspubtd.h
index 5f19a15ce71cbfa5ab5701431646d91677498efe..e9da9278303b6ef2f29427d34ee8ad661e004b71 100644 (file)
--- a/src/dom/js/jspubtd.h
+++ b/src/dom/js/jspubtd.h
JSVERSION_1_4 = 140,
JSVERSION_ECMA_3 = 148,
JSVERSION_1_5 = 150,
+ JSVERSION_1_6 = 160,
JSVERSION_DEFAULT = 0,
JSVERSION_UNKNOWN = -1
} JSVersion;
JSTYPE_STRING, /* string */
JSTYPE_NUMBER, /* number */
JSTYPE_BOOLEAN, /* boolean */
+ JSTYPE_NULL, /* null */
+ JSTYPE_XML, /* xml object */
JSTYPE_LIMIT
} JSType;
/* Struct typedefs. */
typedef struct JSClass JSClass;
+typedef struct JSExtendedClass JSExtendedClass;
typedef struct JSConstDoubleSpec JSConstDoubleSpec;
typedef struct JSContext JSContext;
typedef struct JSErrorReport JSErrorReport;
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;
*
* 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,
* 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);
*/
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
(* 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
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
diff --git a/src/dom/js/jsregexp.c b/src/dom/js/jsregexp.c
index 4d909d4e28403722bc0d0a94759729ac0e088fb7..e9400eb09ce0b80033b12ae35a368be3073b8de1 100644 (file)
--- a/src/dom/js/jsregexp.c
+++ b/src/dom/js/jsregexp.c
/* -*- 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() */
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 */
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;
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 */
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;
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
typedef struct {
REOp op;
const jschar *errPos;
- uint16 parenIndex;
+ size_t parenIndex;
} REOpData;
* 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.
static JSBool
ParseRegExp(CompilerState *state)
{
- uint16 parenIndex;
+ size_t parenIndex;
RENode *operand;
REOpData *operatorStack;
RENode **operandStack;
if (!operandStack)
goto out;
- while (JS_TRUE) {
+ for (;;) {
parenIndex = state->parenCount;
if (state->cp == state->cpend) {
/*
}
} else {
switch (*state->cp) {
- /* balance '(' */
- case '(': /* balance ')' */
+ case '(':
++state->cp;
if (state->cp + 1 < state->cpend &&
*state->cp == '?' &&
} 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;
}
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;
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;
}
break;
}
}
- /* At the end; process remaining operators */
+
+ /* At the end; process remaining operators. */
restartOperator:
if (state->cp == state->cpend) {
while (operatorSP) {
result = JS_TRUE;
goto out;
}
+
switch (*state->cp) {
case '|':
/* Process any stacked 'concat' operators */
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;
}
}
}
++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) {
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))
}
}
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;
}
temp.classCount = 0;
temp.progLength = 0;
temp.treeDepth = 0;
+ temp.classBitmapsMem = 0;
for (i = 0; i < CLASS_CACHE_SIZE; i++)
temp.classCache[i].start = NULL;
if (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;
}
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)
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')
: 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':
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++;
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++;
}
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])
}
}
state->result->u.ucclass.index = state->classCount++;
+
claim:
/*
* Call CalculateBitmapSize now as we want any errors it finds
*/
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;
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;
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;
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) *
emitStateSP = emitStateStack;
op = t->op;
- while (JS_TRUE) {
+ for (;;) {
*pc++ = op;
switch (op) {
case REOP_EMPTY:
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);
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 ==
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;
}
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;
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;
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;
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;
}
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 *)
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;
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;
}
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
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);
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;
}
#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;
}
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;
}
* 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]))
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;
intN nDigits, i;
JS_ASSERT(!charSet->converted);
+ /*
+ * Assert that startIndex and length points to chars inside [] inside
+ * source string.
+ */
+ JS_ASSERT(1 <= charSet->u.src.startIndex);
+ JS_ASSERT(charSet->u.src.startIndex
+ < JSSTRING_LENGTH(gData->regexp->source));
+ JS_ASSERT(charSet->u.src.length <= JSSTRING_LENGTH(gData->regexp->source)
+ - 1 - charSet->u.src.startIndex);
+
charSet->converted = JS_TRUE;
+ src = JSSTRING_CHARS(gData->regexp->source) + charSet->u.src.startIndex;
+ end = src + charSet->u.src.length;
+ JS_ASSERT(src[-1] == '[');
+ JS_ASSERT(end[0] == ']');
byteLength = (charSet->length >> 3) + 1;
charSet->u.bits = (uint8 *)JS_malloc(gData->cx, byteLength);
if (*src == '^') {
JS_ASSERT(charSet->sense == JS_FALSE);
++src;
- }
- else
+ } else {
JS_ASSERT(charSet->sense == JS_TRUE);
-
+ }
while (src != end) {
switch (*src) {
* 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;
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);
{
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;
}
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;
}
}
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;
}
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);
}
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);
{
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;
return NULL;
}
- while (JS_TRUE) {
+ for (;;) {
if (REOP_IS_SIMPLE(op)) {
result = SimpleMatch(gData, x, op, &pc, JS_TRUE);
} else {
*/
case REOP_JUMP:
--gData->stateStackTop;
- offset = GET_OFFSET(pc);
- pc += offset;
+ pc += GET_OFFSET(pc);
op = (REOp) *pc++;
continue;
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;
return NULL;
}
continue;
+
case REOP_ASSERT_NOT:
nextpc = pc + GET_OFFSET(pc);
pc += ARG_LEN;
nextpc, x, x->cp, 0, 0))
return NULL;
continue;
+
case REOP_ASSERTTEST:
--gData->stateStackTop;
--curState;
if (result)
result = x;
break;
+
case REOP_ASSERTNOTTEST:
--gData->stateStackTop;
--curState;
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);
}
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;
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;
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,
/*
* 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;
}
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;
}
break_switch:;
}
+
/*
* If the match failed and there's a backtrack option, take it.
* Otherwise this is a complete and utter failure.
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;
goto out;
}
cp = result->cp;
- i = PTRDIFF(cp, gData.cpbegin, jschar);
+ i = cp - gData.cpbegin;
*indexp = i;
matchlen = i - (start + gData.skipped);
ep = cp;
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;
} 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;
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 {
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"
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);
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;
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))
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};
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) {
* 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;
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);
}
JSString *str;
JSObject *obj;
JSRegExp *re;
+ JSTempValueRooter tvr;
str = js_NewStringCopyN(cx, chars, length, 0);
if (!str)
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;
}
diff --git a/src/dom/js/jsregexp.h b/src/dom/js/jsregexp.h
index 998352df522436a15e474ec5a2be868a2e50e422..50789832d096e0abca4bed21d74e6b2245c6722d 100644 (file)
--- a/src/dom/js/jsregexp.h
+++ b/src/dom/js/jsregexp.h
/*
* 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.
*
*/
union {
uint8 *bits;
struct {
- uint16 startIndex;
- uint16 length;
+ size_t startIndex;
+ size_t length;
} src;
} u;
} RECharSet;
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 */
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);
*/
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
diff --git a/src/dom/js/jsscan.c b/src/dom/js/jsscan.c
index 995c1e660a6ab64b7034b04ef05f07b4a0e55804..c043799dc05d438f3e6e6866fa487e68739cceeb 100644 (file)
--- a/src/dom/js/jsscan.c
+++ b/src/dom/js/jsscan.c
/* -*- 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 */
{"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},
{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},
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);
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)
{
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;
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;
/* 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;
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)
{
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--)
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) {
* 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
/*
*/
/*
- * 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)
{
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.
}
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;
}
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)
/* 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;
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);
}
} 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);
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;
}
}
* 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")) {
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;
}
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;
}
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;
}
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;
}
}
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.
}
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, '!');
}
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;
}
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);
}
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(),
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
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;
}
(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,
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;
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
diff --git a/src/dom/js/jsscan.h b/src/dom/js/jsscan.h
index 121b35df31c32d8b4bce59546e1cd4767783f710..ee39bbc0af85f987ae2a196c25a1db736f99e739 100644 (file)
--- a/src/dom/js/jsscan.h
+++ b/src/dom/js/jsscan.h
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;
#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 */
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 {
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 */
#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
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.
*/
* 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.
diff --git a/src/dom/js/jsscope.c b/src/dom/js/jsscope.c
index e3603b18f699e1e67ec523eaffe0ad1794770468..4f951238724ef76db9878fa8f1fdba1328f0a77d 100644 (file)
--- a/src/dom/js/jsscope.c
+++ b/src/dom/js/jsscope.c
}
static JSBool
-CreateScopeTable(JSScope *scope)
+CreateScopeTable(JSContext *cx, JSScope *scope, JSBool report)
{
int sizeLog2;
JSScopeProperty *sprop, **spp;
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) {
js_InitObjectMap(&scope->map, nrefs, ops, clasp);
scope->object = obj;
scope->flags = 0;
+ scope->dswIndex = 0;
InitMinimalScope(scope);
#ifdef JS_THREADSAFE
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);
/* 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;
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 {
if (!parent) {
entry->child = sprop;
} else {
- if (!InsertPropertyTreeChild(rt, parent, sprop))
+ if (!InsertPropertyTreeChild(rt, parent, sprop, NULL))
goto out_of_memory;
}
* 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);
}
* 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);
/* 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);
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);
/* 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;
+ }
}
}
diff --git a/src/dom/js/jsscope.h b/src/dom/js/jsscope.h
index 8ac7ef073bca5db696cd2f9dd9e67f7af6fee765..0f8a837c0f8a47c994e163c7f9d863a06cecdf04 100644 (file)
--- a/src/dom/js/jsscope.h
+++ b/src/dom/js/jsscope.h
* 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 */
#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);
diff --git a/src/dom/js/jsscript.c b/src/dom/js/jsscript.c
index 7e5aefc306cca12aa6a0d3a9a236cb3588bbc606..6fc92de930109afc9598501a0f9cfcf6a87fe23e 100644 (file)
--- a/src/dom/js/jsscript.c
+++ b/src/dom/js/jsscript.c
/* -*- 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
#if JS_HAS_SCRIPT_OBJECT
+static const char js_script_exec[] = "Script.prototype.exec";
+static const char js_script_compile[] = "Script.prototype.compile";
+
#if JS_HAS_TOSOURCE
static JSBool
script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSScript *oldscript, *script;
- JSString *str;
JSStackFrame *fp, *caller;
+ JSString *str;
JSObject *scopeobj;
const char *file;
uintN line;
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;
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
* 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),
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;
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);
}
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);
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);
}
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;
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;
#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);
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)
{
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
}
}
}
-void
-js_DestroyScript(JSContext *cx, JSScript *script)
+JS_FRIEND_API(void)
+js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
{
JSRuntime *rt;
JSDestroyScriptHook hook;
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);
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) {
lineno++;
}
}
+ if (best >= 0)
+ offset = best;
+out:
return script->code + offset;
}
-uintN
+JS_FRIEND_API(uintN)
js_GetScriptLineExtent(JSScript *script)
{
uintN lineno;
diff --git a/src/dom/js/jsscript.h b/src/dom/js/jsscript.h
index 6284917afe95b35b88d0ff13afeb01223319043a..77f59ed751440e8dcffd6f2f8de8334443e3c00c 100644 (file)
--- a/src/dom/js/jsscript.h
+++ b/src/dom/js/jsscript.h
/*
* 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 {
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);
extern JS_FRIEND_API(void)
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
+extern JS_FRIEND_API(void)
+js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
+
extern void
js_DestroyScript(JSContext *cx, JSScript *script);
extern jsbytecode *
js_LineNumberToPC(JSScript *script, uintN lineno);
-extern uintN
+extern JS_FRIEND_API(uintN)
js_GetScriptLineExtent(JSScript *script);
/*
diff --git a/src/dom/js/jsstddef.h b/src/dom/js/jsstddef.h
index 0d87b0c0c7cb8fb92838d590f4f6736f7d1942a7..addaa88ff6f08fb98fe05b0ae6b874564dd06cf5 100644 (file)
--- a/src/dom/js/jsstddef.h
+++ b/src/dom/js/jsstddef.h
#else /*WIN16*/
#define PTRDIFF(p1, p2, type) \
- ((p1) - (p2))
+ ((p1) - (p2))
#endif
diff --git a/src/dom/js/jsstr.c b/src/dom/js/jsstr.c
index e143ab8dfcac4d49f458191129072c18db9a23dc..5e0bafd3ba626251b130058f88f1f40682c3b6ac 100644 (file)
--- a/src/dom/js/jsstr.c
+++ b/src/dom/js/jsstr.c
/* -*- 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
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)
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));
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));
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;
}
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
};
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;
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;
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)
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);
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)
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);
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;
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;
}
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;
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 {
* 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;
data->regexp = NULL;
js_DestroyRegExp(cx, re);
}
+
return ok;
}
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
} 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;
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++;
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,
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
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. */
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 */
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;
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;
*/
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. */
* 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;
}
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;
* 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;
/*
* 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;
}
#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))
*/
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;
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;
if (param) {
tagbuf[j++] = '=';
tagbuf[j++] = '"';
- js_strncpy(&tagbuf[j], param, parlen);
+ js_strncpy(&tagbuf[j], JSSTRING_CHARS(param), parlen);
j += parlen;
tagbuf[j++] = '"';
}
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
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. */
str = js_ValueToString(cx, argv[0]);
if (!str)
return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str);
} else {
str = cx->runtime->emptyString;
}
{
JSRuntime *rt;
JSString *empty;
+ JSAtom *atom;
rt = cx->runtime;
JS_ASSERT(!rt->emptyString);
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;
}
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)
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;
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) {
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
{
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)
{
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)) {
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
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;
}
/*
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)
{
*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
* 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
*/
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 */
};
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;
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) {
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];
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;
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;
}
}
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);
}
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;
JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
}
- if (ucs4Char < minucs4Char ||
+ if (ucs4Char < minucs4Char ||
ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
ucs4Char = 0xFFFD;
}
diff --git a/src/dom/js/jsstr.h b/src/dom/js/jsstr.h
index 202d0d9ea7c4571e7a91f8d0723c97279229870a..658a87f90f4c328b92274a546644fd1de011e42b 100644 (file)
--- a/src/dom/js/jsstr.h
+++ b/src/dom/js/jsstr.h
#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)
*/
#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))
? (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')
js_FinishRuntimeStringState(JSContext *cx);
/* Initialize the String class, returning its prototype object. */
+extern JSClass js_StringClass;
+
extern JSObject *
js_InitStringClass(JSContext *cx, JSObject *obj);
extern JSObject *
js_StringToObject(JSContext *cx, JSString *str);
+/*
+ * Convert a value to a printable C string.
+ */
+extern JS_FRIEND_API(const char *)
+js_ValueToPrintableString(JSContext *cx, jsval v);
+
/*
* Convert a value to a string, returning null after reporting an error,
* otherwise returning a new string reference.
extern JSString *
js_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.
*/
/*
* 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
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
+/*
+ * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
+ * least 6 bytes long. Return the number of UTF-8 bytes of data written.
+ */
+extern int
+js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char);
+
JS_END_EXTERN_C
#endif /* jsstr_h___ */
diff --git a/src/dom/js/jstypes.h b/src/dom/js/jstypes.h
index 35fc12e54bf78ae89e39ada032fbed66c1df7a7c..1c24293b5357795425131f29bfc0d5a87f138c31 100644 (file)
--- a/src/dom/js/jstypes.h
+++ b/src/dom/js/jstypes.h
#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
#include "jsotypes.h"
+/***********************************************************************
+** MACROS: JS_LIKELY
+** JS_UNLIKELY
+** DESCRIPTION:
+** These macros allow you to give a hint to the compiler about branch
+** probability so that it can better optimize. Use them like this:
+**
+** if (JS_LIKELY(v == 1)) {
+** ... expected code path ...
+** }
+**
+** if (JS_UNLIKELY(v == 0)) {
+** ... non-expected code path ...
+** }
+**
+***********************************************************************/
+#if defined(__GNUC__) && (__GNUC__ > 2)
+#define JS_LIKELY(x) (__builtin_expect((x), 1))
+#define JS_UNLIKELY(x) (__builtin_expect((x), 0))
+#else
+#define JS_LIKELY(x) (x)
+#define JS_UNLIKELY(x) (x)
+#endif
+
JS_END_EXTERN_C
#endif /* jstypes_h___ */
-
diff --git a/src/dom/js/jsutil.c b/src/dom/js/jsutil.c
index 6e4c21cade88373a10a1c3b9266732f1b0001a2d..d7fab0f88fb8cef4b412d4f1f7665864f3a5ed67 100644 (file)
--- a/src/dom/js/jsutil.c
+++ b/src/dom/js/jsutil.c
# 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 */
diff --git a/src/dom/js/jsutil.h b/src/dom/js/jsutil.h
index a34096d9351d2f6f703472e267912a30f7511471..5e26c16ae3128d6601be3675dd7e6cdcdd28168f 100644 (file)
--- a/src/dom/js/jsutil.h
+++ b/src/dom/js/jsutil.h
*/
extern JS_PUBLIC_API(void) JS_Abort(void);
+#ifdef XP_UNIX
+
+typedef struct JSCallsite JSCallsite;
+
+struct JSCallsite {
+ uint32 pc;
+ char *name;
+ const char *library;
+ int offset;
+ JSCallsite *parent;
+ JSCallsite *siblings;
+ JSCallsite *kids;
+ void *handy;
+};
+
+extern JSCallsite *JS_Backtrace(int skip);
+
+#endif
+
JS_END_EXTERN_C
#endif /* jsutil_h___ */
diff --git a/src/dom/js/jsxdrapi.c b/src/dom/js/jsxdrapi.c
index e956072f9a32b0c629caa48972656fc81413829e..0c9aeceedf01acea39ccf618ff4b3e03a4a16fe4 100644 (file)
--- a/src/dom/js/jsxdrapi.c
+++ b/src/dom/js/jsxdrapi.c
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
--- /dev/null
+++ b/src/dom/js/jsxml.c
@@ -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[] = "&";
+const char js_gt_entity_str[] = ">";
+const char js_lt_entity_str[] = "<";
+const char js_quot_entity_str[] = """;
+
+#define IS_EMPTY(str) (JSSTRING_LENGTH(str) == 0)
+#define IS_STAR(str) (JSSTRING_LENGTH(str) == 1 && *JSSTRING_CHARS(str) == '*')
+
+static JSBool
+xml_isXMLName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ *rval = BOOLEAN_TO_JSVAL(js_IsXMLName(cx, argv[0]));
+ return JS_TRUE;
+}
+
+/*
+ * Namespace class and library functions.
+ */
+enum namespace_tinyid {
+ NAMESPACE_PREFIX = -1,
+ NAMESPACE_URI = -2
+};
+
+static JSBool
+namespace_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSXMLNamespace *ns;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+
+ ns = (JSXMLNamespace *)
+ JS_GetInstancePrivate(cx, obj, &js_NamespaceClass.base, NULL);
+ if (!ns)
+ return JS_TRUE;
+
+ switch (JSVAL_TO_INT(id)) {
+ case NAMESPACE_PREFIX:
+ *vp = ns->prefix ? STRING_TO_JSVAL(ns->prefix) : JSVAL_VOID;
+ break;
+ case NAMESPACE_URI:
+ *vp = STRING_TO_JSVAL(ns->uri);
+ break;
+ }
+ return JS_TRUE;
+}
+
+static void
+namespace_finalize(JSContext *cx, JSObject *obj)
+{
+ JSXMLNamespace *ns;
+ JSRuntime *rt;
+
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, obj);
+ if (!ns)
+ return;
+ JS_ASSERT(ns->object == obj);
+ ns->object = NULL;
+ UNMETER(xml_stats.livenamespaceobj);
+
+ rt = cx->runtime;
+ if (rt->functionNamespaceObject == obj)
+ rt->functionNamespaceObject = NULL;
+}
+
+static void
+namespace_mark_vector(JSContext *cx, JSXMLNamespace **vec, uint32 len,
+ void *arg)
+{
+ uint32 i;
+ JSXMLNamespace *ns;
+
+ for (i = 0; i < len; i++) {
+ ns = vec[i];
+ {
+#ifdef GC_MARK_DEBUG
+ char buf[100];
+
+ JS_snprintf(buf, sizeof buf, "%s=%s",
+ ns->prefix ? JS_GetStringBytes(ns->prefix) : "",
+ JS_GetStringBytes(ns->uri));
+#else
+ const char *buf = NULL;
+#endif
+ JS_MarkGCThing(cx, ns, buf, arg);
+ }
+ }
+}
+
+static uint32
+namespace_mark(JSContext *cx, JSObject *obj, void *arg)
+{
+ JSXMLNamespace *ns;
+
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, obj);
+ JS_MarkGCThing(cx, ns, js_private_str, arg);
+ return 0;
+}
+
+static JSBool
+namespace_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+{
+ JSXMLNamespace *ns, *ns2;
+ JSObject *obj2;
+
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, obj);
+ JS_ASSERT(JSVAL_IS_OBJECT(v));
+ obj2 = JSVAL_TO_OBJECT(v);
+ if (!obj2 || OBJ_GET_CLASS(cx, obj2) != &js_NamespaceClass.base) {
+ *bp = JS_FALSE;
+ } else {
+ ns2 = (JSXMLNamespace *) JS_GetPrivate(cx, obj2);
+ *bp = !js_CompareStrings(ns->uri, ns2->uri);
+ }
+ return JS_TRUE;
+}
+
+JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass = {
+ { "Namespace",
+ JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED,
+ JS_PropertyStub, JS_PropertyStub, namespace_getProperty, NULL,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, namespace_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, namespace_mark, NULL },
+ namespace_equality,
+ NULL, NULL,
+ JSCLASS_NO_RESERVED_MEMBERS
+};
+
+#define NAMESPACE_ATTRS \
+ (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
+
+static JSPropertySpec namespace_props[] = {
+ {js_prefix_str, NAMESPACE_PREFIX, NAMESPACE_ATTRS, 0, 0},
+ {js_uri_str, NAMESPACE_URI, NAMESPACE_ATTRS, 0, 0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+namespace_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXMLNamespace *ns;
+
+ ns = (JSXMLNamespace *)
+ JS_GetInstancePrivate(cx, obj, &js_NamespaceClass.base, argv);
+ if (!ns)
+ return JS_FALSE;
+
+ *rval = STRING_TO_JSVAL(ns->uri);
+ return JS_TRUE;
+}
+
+static JSFunctionSpec namespace_methods[] = {
+ {js_toString_str, namespace_toString, 0,0,0},
+ {0,0,0,0,0}
+};
+
+JSXMLNamespace *
+js_NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri,
+ JSBool declared)
+{
+ JSXMLNamespace *ns;
+
+ ns = (JSXMLNamespace *)
+ js_NewGCThing(cx, GCX_NAMESPACE, sizeof(JSXMLNamespace));
+ if (!ns)
+ return NULL;
+ ns->object = NULL;
+ ns->prefix = prefix;
+ ns->uri = uri;
+ ns->declared = declared;
+ METER(xml_stats.namespace);
+ METER(xml_stats.livenamespace);
+ return ns;
+}
+
+void
+js_MarkXMLNamespace(JSContext *cx, JSXMLNamespace *ns, void *arg)
+{
+ JS_MarkGCThing(cx, ns->object, js_object_str, arg);
+ JS_MarkGCThing(cx, ns->prefix, js_prefix_str, arg);
+ JS_MarkGCThing(cx, ns->uri, js_uri_str, arg);
+}
+
+void
+js_FinalizeXMLNamespace(JSContext *cx, JSXMLNamespace *ns)
+{
+ UNMETER(xml_stats.livenamespace);
+}
+
+JSObject *
+js_NewXMLNamespaceObject(JSContext *cx, JSString *prefix, JSString *uri,
+ JSBool declared)
+{
+ JSXMLNamespace *ns;
+
+ ns = js_NewXMLNamespace(cx, prefix, uri, declared);
+ if (!ns)
+ return NULL;
+ return js_GetXMLNamespaceObject(cx, ns);
+}
+
+JSObject *
+js_GetXMLNamespaceObject(JSContext *cx, JSXMLNamespace *ns)
+{
+ JSObject *obj;
+
+ obj = ns->object;
+ if (obj) {
+ JS_ASSERT(JS_GetPrivate(cx, obj) == ns);
+ return obj;
+ }
+ obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL);
+ if (!obj || !JS_SetPrivate(cx, obj, ns)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ ns->object = obj;
+ METER(xml_stats.namespaceobj);
+ METER(xml_stats.livenamespaceobj);
+ return obj;
+}
+
+/*
+ * QName class and library functions.
+ */
+enum qname_tinyid {
+ QNAME_URI = -1,
+ QNAME_LOCALNAME = -2
+};
+
+static JSBool
+qname_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSXMLQName *qn;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+
+ qn = (JSXMLQName *)
+ JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, NULL);
+ if (!qn)
+ return JS_TRUE;
+
+ switch (JSVAL_TO_INT(id)) {
+ case QNAME_URI:
+ *vp = qn->uri ? STRING_TO_JSVAL(qn->uri) : JSVAL_NULL;
+ break;
+ case QNAME_LOCALNAME:
+ *vp = STRING_TO_JSVAL(qn->localName);
+ break;
+ }
+ return JS_TRUE;
+}
+
+static void
+qname_finalize(JSContext *cx, JSObject *obj)
+{
+ JSXMLQName *qn;
+
+ qn = (JSXMLQName *) JS_GetPrivate(cx, obj);
+ if (!qn)
+ return;
+ JS_ASSERT(qn->object == obj);
+ qn->object = NULL;
+ UNMETER(xml_stats.liveqnameobj);
+}
+
+static void
+anyname_finalize(JSContext* cx, JSObject* obj)
+{
+ JSRuntime *rt;
+
+ /* Make sure the next call to js_GetAnyName doesn't try to use obj. */
+ rt = cx->runtime;
+ if (rt->anynameObject == obj)
+ rt->anynameObject = NULL;
+
+ qname_finalize(cx, obj);
+}
+
+static uint32
+qname_mark(JSContext *cx, JSObject *obj, void *arg)
+{
+ JSXMLQName *qn;
+
+ qn = (JSXMLQName *) JS_GetPrivate(cx, obj);
+ JS_MarkGCThing(cx, qn, js_private_str, arg);
+ return 0;
+}
+
+static JSBool
+qname_identity(JSXMLQName *qna, JSXMLQName *qnb)
+{
+ if (!qna->uri ^ !qnb->uri)
+ return JS_FALSE;
+ if (qna->uri && js_CompareStrings(qna->uri, qnb->uri))
+ return JS_FALSE;
+ return !js_CompareStrings(qna->localName, qnb->localName);
+}
+
+static JSBool
+qname_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+{
+ JSXMLQName *qn, *qn2;
+ JSObject *obj2;
+
+ qn = (JSXMLQName *) JS_GetPrivate(cx, obj);
+ JS_ASSERT(JSVAL_IS_OBJECT(v));
+ obj2 = JSVAL_TO_OBJECT(v);
+ if (!obj2 || OBJ_GET_CLASS(cx, obj2) != &js_QNameClass.base) {
+ *bp = JS_FALSE;
+ } else {
+ qn2 = (JSXMLQName *) JS_GetPrivate(cx, obj2);
+ *bp = qname_identity(qn, qn2);
+ }
+ return JS_TRUE;
+}
+
+JS_FRIEND_DATA(JSExtendedClass) js_QNameClass = {
+ { "QName",
+ JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED,
+ JS_PropertyStub, JS_PropertyStub, qname_getProperty, NULL,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, qname_mark, NULL },
+ qname_equality,
+ NULL, NULL,
+ JSCLASS_NO_RESERVED_MEMBERS
+};
+
+/*
+ * Classes for the ECMA-357-internal types AttributeName and AnyName, which
+ * are like QName, except that they have no property getters. They share the
+ * qname_toString method, and therefore are exposed as constructable objects
+ * in this implementation.
+ */
+JS_FRIEND_DATA(JSClass) js_AttributeNameClass = {
+ js_AttributeName_str, JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, qname_mark, NULL
+};
+
+JS_FRIEND_DATA(JSClass) js_AnyNameClass = {
+ js_AnyName_str, JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, anyname_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, qname_mark, NULL
+};
+
+#define QNAME_ATTRS \
+ (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
+
+static JSPropertySpec qname_props[] = {
+ {js_uri_str, QNAME_URI, QNAME_ATTRS, 0, 0},
+ {js_localName_str, QNAME_LOCALNAME, QNAME_ATTRS, 0, 0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+qname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSClass *clasp;
+ JSXMLQName *qn;
+ JSString *str, *qualstr;
+ size_t length;
+ jschar *chars;
+
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if (clasp == &js_AttributeNameClass || clasp == &js_AnyNameClass) {
+ qn = (JSXMLQName *) JS_GetPrivate(cx, obj);
+ } else {
+ qn = (JSXMLQName *)
+ JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, argv);
+ if (!qn)
+ return JS_FALSE;
+ }
+
+ if (!qn->uri) {
+ /* No uri means wildcard qualifier. */
+ str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom);
+ } else if (IS_EMPTY(qn->uri)) {
+ /* Empty string for uri means localName is in no namespace. */
+ str = cx->runtime->emptyString;
+ } else {
+ qualstr = ATOM_TO_STRING(cx->runtime->atomState.qualifierAtom);
+ str = js_ConcatStrings(cx, qn->uri, qualstr);
+ if (!str)
+ return JS_FALSE;
+ }
+ str = js_ConcatStrings(cx, str, qn->localName);
+ if (!str)
+ return JS_FALSE;
+
+ if (str && clasp == &js_AttributeNameClass) {
+ length = JSSTRING_LENGTH(str);
+ chars = (jschar *) JS_malloc(cx, (length + 2) * sizeof(jschar));
+ if (!chars)
+ return JS_FALSE;
+ *chars = '@';
+ js_strncpy(chars + 1, JSSTRING_CHARS(str), length);
+ chars[++length] = 0;
+ str = js_NewString(cx, chars, length, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ return JS_FALSE;
+ }
+ }
+
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSFunctionSpec qname_methods[] = {
+ {js_toString_str, qname_toString, 0,0,0},
+ {0,0,0,0,0}
+};
+
+JSXMLQName *
+js_NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix,
+ JSString *localName)
+{
+ JSXMLQName *qn;
+
+ qn = (JSXMLQName *) js_NewGCThing(cx, GCX_QNAME, sizeof(JSXMLQName));
+ if (!qn)
+ return NULL;
+ qn->object = NULL;
+ qn->uri = uri;
+ qn->prefix = prefix;
+ qn->localName = localName;
+ METER(xml_stats.qname);
+ METER(xml_stats.liveqname);
+ return qn;
+}
+
+void
+js_MarkXMLQName(JSContext *cx, JSXMLQName *qn, void *arg)
+{
+ JS_MarkGCThing(cx, qn->object, js_object_str, arg);
+ JS_MarkGCThing(cx, qn->uri, js_uri_str, arg);
+ JS_MarkGCThing(cx, qn->prefix, js_prefix_str, arg);
+ JS_MarkGCThing(cx, qn->localName, js_localName_str, arg);
+}
+
+void
+js_FinalizeXMLQName(JSContext *cx, JSXMLQName *qn)
+{
+ UNMETER(xml_stats.liveqname);
+}
+
+JSObject *
+js_NewXMLQNameObject(JSContext *cx, JSString *uri, JSString *prefix,
+ JSString *localName)
+{
+ JSXMLQName *qn;
+
+ qn = js_NewXMLQName(cx, uri, prefix, localName);
+ if (!qn)
+ return NULL;
+ return js_GetXMLQNameObject(cx, qn);
+}
+
+JSObject *
+js_GetXMLQNameObject(JSContext *cx, JSXMLQName *qn)
+{
+ JSObject *obj;
+
+ obj = qn->object;
+ if (obj) {
+ JS_ASSERT(JS_GetPrivate(cx, obj) == qn);
+ return obj;
+ }
+ obj = js_NewObject(cx, &js_QNameClass.base, NULL, NULL);
+ if (!obj || !JS_SetPrivate(cx, obj, qn)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ qn->object = obj;
+ METER(xml_stats.qnameobj);
+ METER(xml_stats.liveqnameobj);
+ return obj;
+}
+
+JSObject *
+js_GetAttributeNameObject(JSContext *cx, JSXMLQName *qn)
+{
+ JSObject *obj;
+
+ obj = qn->object;
+ if (obj) {
+ if (OBJ_GET_CLASS(cx, obj) == &js_AttributeNameClass)
+ return obj;
+ qn = js_NewXMLQName(cx, qn->uri, qn->prefix, qn->localName);
+ if (!qn)
+ return NULL;
+ }
+
+ obj = js_NewObject(cx, &js_AttributeNameClass, NULL, NULL);
+ if (!obj || !JS_SetPrivate(cx, obj, qn)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+
+ qn->object = obj;
+ METER(xml_stats.qnameobj);
+ METER(xml_stats.liveqnameobj);
+ return obj;
+}
+
+JSObject *
+js_ConstructXMLQNameObject(JSContext *cx, jsval nsval, jsval lnval)
+{
+ jsval argv[2];
+
+ /*
+ * ECMA-357 11.1.2,
+ * The _QualifiedIdentifier : PropertySelector :: PropertySelector_
+ * production, step 2.
+ */
+ if (!JSVAL_IS_PRIMITIVE(nsval) &&
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(nsval)) == &js_AnyNameClass) {
+ nsval = JSVAL_NULL;
+ }
+
+ argv[0] = nsval;
+ argv[1] = lnval;
+ return js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, argv);
+}
+
+static JSBool
+IsXMLName(const jschar *cp, size_t n)
+{
+ JSBool rv;
+ jschar c;
+
+ rv = JS_FALSE;
+ if (n != 0 && JS_ISXMLNSSTART(*cp)) {
+ while (--n != 0) {
+ c = *++cp;
+ if (!JS_ISXMLNS(c))
+ return rv;
+ }
+ rv = JS_TRUE;
+ }
+ return rv;
+}
+
+JSBool
+js_IsXMLName(JSContext *cx, jsval v)
+{
+ JSClass *clasp;
+ JSXMLQName *qn;
+ JSString *name;
+ JSErrorReporter older;
+
+ /*
+ * Inline specialization of the QName constructor called with v passed as
+ * the only argument, to compute the localName for the constructed qname,
+ * without actually allocating the object or computing its uri and prefix.
+ * See ECMA-357 13.1.2.1 step 1 and 13.3.2.
+ */
+ if (!JSVAL_IS_PRIMITIVE(v) &&
+ (clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)),
+ clasp == &js_QNameClass.base ||
+ clasp == &js_AttributeNameClass ||
+ clasp == &js_AnyNameClass)) {
+ qn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ name = qn->localName;
+ } else {
+ older = JS_SetErrorReporter(cx, NULL);
+ name = js_ValueToString(cx, v);
+ JS_SetErrorReporter(cx, older);
+ if (!name) {
+ JS_ClearPendingException(cx);
+ return JS_FALSE;
+ }
+ }
+
+ return IsXMLName(JSSTRING_CHARS(name), JSSTRING_LENGTH(name));
+}
+
+static JSBool
+Namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval urival, prefixval;
+ JSObject *uriobj;
+ JSBool isNamespace, isQName;
+ JSClass *clasp;
+ JSString *empty, *prefix;
+ JSXMLNamespace *ns, *ns2;
+ JSXMLQName *qn;
+
+ urival = argv[argc > 1];
+ isNamespace = isQName = JS_FALSE;
+ if (!JSVAL_IS_PRIMITIVE(urival)) {
+ uriobj = JSVAL_TO_OBJECT(urival);
+ clasp = OBJ_GET_CLASS(cx, uriobj);
+ isNamespace = (clasp == &js_NamespaceClass.base);
+ isQName = (clasp == &js_QNameClass.base);
+ }
+#ifdef __GNUC__ /* suppress bogus gcc warnings */
+ else uriobj = NULL;
+#endif
+
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ /* Namespace called as function. */
+ if (argc == 1 && isNamespace) {
+ /* Namespace called with one Namespace argument is identity. */
+ *rval = urival;
+ return JS_TRUE;
+ }
+
+ /* Create and return a new QName object exactly as if constructed. */
+ obj = js_NewObject(cx, &js_NamespaceClass.base, NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ }
+ METER(xml_stats.namespaceobj);
+ METER(xml_stats.livenamespaceobj);
+
+ /*
+ * Create and connect private data to rooted obj early, so we don't have
+ * to worry about rooting string newborns hanging off of the private data
+ * further below.
+ */
+ empty = cx->runtime->emptyString;
+ ns = js_NewXMLNamespace(cx, empty, empty, JS_FALSE);
+ if (!ns)
+ return JS_FALSE;
+ if (!JS_SetPrivate(cx, obj, ns))
+ return JS_FALSE;
+ ns->object = obj;
+
+ if (argc == 1) {
+ if (isNamespace) {
+ ns2 = (JSXMLNamespace *) JS_GetPrivate(cx, uriobj);
+ ns->uri = ns2->uri;
+ ns->prefix = ns2->prefix;
+ } else if (isQName &&
+ (qn = (JSXMLQName *) JS_GetPrivate(cx, uriobj))->uri) {
+ ns->uri = qn->uri;
+ ns->prefix = qn->prefix;
+ } else {
+ ns->uri = js_ValueToString(cx, urival);
+ if (!ns->uri)
+ return JS_FALSE;
+
+ /* NULL here represents *undefined* in ECMA-357 13.2.2 3(c)iii. */
+ if (!IS_EMPTY(ns->uri))
+ ns->prefix = NULL;
+ }
+ } else if (argc == 2) {
+ if (isQName &&
+ (qn = (JSXMLQName *) JS_GetPrivate(cx, uriobj))->uri) {
+ ns->uri = qn->uri;
+ } else {
+ ns->uri = js_ValueToString(cx, urival);
+ if (!ns->uri)
+ return JS_FALSE;
+ }
+
+ prefixval = argv[0];
+ if (IS_EMPTY(ns->uri)) {
+ if (!JSVAL_IS_VOID(prefixval)) {
+ prefix = js_ValueToString(cx, prefixval);
+ if (!prefix)
+ return JS_FALSE;
+ if (!IS_EMPTY(prefix)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_XML_NAMESPACE,
+ js_ValueToPrintableString(cx,
+ STRING_TO_JSVAL(prefix)));
+ return JS_FALSE;
+ }
+ }
+ } else if (JSVAL_IS_VOID(prefixval) || !js_IsXMLName(cx, prefixval)) {
+ /* NULL here represents *undefined* in ECMA-357 13.2.2 4(d) etc. */
+ ns->prefix = NULL;
+ } else {
+ prefix = js_ValueToString(cx, prefixval);
+ if (!prefix)
+ return JS_FALSE;
+ ns->prefix = prefix;
+ }
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+QName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval nameval, nsval;
+ JSBool isQName, isNamespace;
+ JSXMLQName *qn;
+ JSString *uri, *prefix, *name;
+ JSObject *nsobj;
+ JSClass *clasp;
+ JSXMLNamespace *ns;
+
+ nameval = argv[argc > 1];
+ isQName =
+ !JSVAL_IS_PRIMITIVE(nameval) &&
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(nameval)) == &js_QNameClass.base;
+
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+ /* QName called as function. */
+ if (argc == 1 && isQName) {
+ /* QName called with one QName argument is identity. */
+ *rval = nameval;
+ return JS_TRUE;
+ }
+
+ /*
+ * Create and return a new QName object exactly as if constructed.
+ * Use the constructor's clasp so we can be shared by AttributeName
+ * (see below after this function).
+ */
+ obj = js_NewObject(cx,
+ argv
+ ? JS_ValueToFunction(cx, argv[-2])->clasp
+ : &js_QNameClass.base,
+ NULL, NULL);
+ if (!obj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ }
+ METER(xml_stats.qnameobj);
+ METER(xml_stats.liveqnameobj);
+
+ if (isQName) {
+ /* If namespace is not specified and name is a QName, clone it. */
+ qn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(nameval));
+ if (argc == 1) {
+ uri = qn->uri;
+ prefix = qn->prefix;
+ name = qn->localName;
+ goto out;
+ }
+
+ /* Namespace and qname were passed -- use the qname's localName. */
+ nameval = STRING_TO_JSVAL(qn->localName);
+ }
+
+ if (argc == 0) {
+ name = cx->runtime->emptyString;
+ } else {
+ name = js_ValueToString(cx, nameval);
+ if (!name)
+ return JS_FALSE;
+
+ /* Use argv[1] as a local root for name, even if it was not passed. */
+ argv[1] = STRING_TO_JSVAL(name);
+ }
+
+ nsval = argv[0];
+ if (argc == 1 || JSVAL_IS_VOID(nsval)) {
+ if (IS_STAR(name)) {
+ nsval = JSVAL_NULL;
+ } else {
+ if (!js_GetDefaultXMLNamespace(cx, &nsval))
+ return JS_FALSE;
+ }
+ }
+
+ if (JSVAL_IS_NULL(nsval)) {
+ /* NULL prefix represents *undefined* in ECMA-357 13.3.2 5(a). */
+ uri = prefix = NULL;
+ } else {
+ /*
+ * Inline specialization of the Namespace constructor called with
+ * nsval passed as the only argument, to compute the uri and prefix
+ * for the constructed namespace, without actually allocating the
+ * object or computing other members. See ECMA-357 13.3.2 6(a) and
+ * 13.2.2.
+ */
+ isNamespace = isQName = JS_FALSE;
+ if (!JSVAL_IS_PRIMITIVE(nsval)) {
+ nsobj = JSVAL_TO_OBJECT(nsval);
+ clasp = OBJ_GET_CLASS(cx, nsobj);
+ isNamespace = (clasp == &js_NamespaceClass.base);
+ isQName = (clasp == &js_QNameClass.base);
+ }
+#ifdef __GNUC__ /* suppress bogus gcc warnings */
+ else nsobj = NULL;
+#endif
+
+ if (isNamespace) {
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj);
+ uri = ns->uri;
+ prefix = ns->prefix;
+ } else if (isQName &&
+ (qn = (JSXMLQName *) JS_GetPrivate(cx, nsobj))->uri) {
+ uri = qn->uri;
+ prefix = qn->prefix;
+ } else {
+ uri = js_ValueToString(cx, nsval);
+ if (!uri)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(uri); /* local root */
+
+ /* NULL here represents *undefined* in ECMA-357 13.2.2 3(c)iii. */
+ prefix = IS_EMPTY(uri) ? cx->runtime->emptyString : NULL;
+ }
+ }
+
+out:
+ qn = js_NewXMLQName(cx, uri, prefix, name);
+ if (!qn)
+ return JS_FALSE;
+ if (!JS_SetPrivate(cx, obj, qn))
+ return JS_FALSE;
+ qn->object = obj;
+ return JS_TRUE;
+}
+
+static JSBool
+AttributeName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ /*
+ * Since js_AttributeNameClass was initialized, obj will have that as its
+ * class, not js_QNameClass.
+ */
+ return QName(cx, obj, argc, argv, rval);
+}
+
+/*
+ * XMLArray library functions.
+ */
+static JSBool
+namespace_identity(const void *a, const void *b)
+{
+ const JSXMLNamespace *nsa = (const JSXMLNamespace *) a;
+ const JSXMLNamespace *nsb = (const JSXMLNamespace *) b;
+
+ if (nsa->prefix && nsb->prefix) {
+ if (js_CompareStrings(nsa->prefix, nsb->prefix))
+ return JS_FALSE;
+ } else {
+ if (nsa->prefix || nsb->prefix)
+ return JS_FALSE;
+ }
+ return !js_CompareStrings(nsa->uri, nsb->uri);
+}
+
+static JSBool
+attr_identity(const void *a, const void *b)
+{
+ const JSXML *xmla = (const JSXML *) a;
+ const JSXML *xmlb = (const JSXML *) b;
+
+ return qname_identity(xmla->name, xmlb->name);
+}
+
+static void
+XMLArrayCursorInit(JSXMLArrayCursor *cursor, JSXMLArray *array)
+{
+ JSXMLArrayCursor *next;
+
+ cursor->array = array;
+ cursor->index = 0;
+ next = cursor->next = array->cursors;
+ if (next)
+ next->prevp = &cursor->next;
+ cursor->prevp = &array->cursors;
+ array->cursors = cursor;
+ cursor->root = NULL;
+}
+
+static void
+XMLArrayCursorFinish(JSXMLArrayCursor *cursor)
+{
+ JSXMLArrayCursor *next;
+
+ if (!cursor->array)
+ return;
+ next = cursor->next;
+ if (next)
+ next->prevp = cursor->prevp;
+ *cursor->prevp = next;
+ cursor->array = NULL;
+}
+
+static void *
+XMLArrayCursorNext(JSXMLArrayCursor *cursor)
+{
+ JSXMLArray *array;
+
+ array = cursor->array;
+ if (!array || cursor->index >= array->length)
+ return NULL;
+ return cursor->root = array->vector[cursor->index++];
+}
+
+static void *
+XMLArrayCursorItem(JSXMLArrayCursor *cursor)
+{
+ JSXMLArray *array;
+
+ array = cursor->array;
+ if (!array || cursor->index >= array->length)
+ return NULL;
+ return cursor->root = array->vector[cursor->index];
+}
+
+static void
+XMLArrayCursorMark(JSContext *cx, JSXMLArrayCursor *cursor)
+{
+ while (cursor) {
+ GC_MARK(cx, cursor->root, "cursor->root", NULL);
+ cursor = cursor->next;
+ }
+}
+
+/* NB: called with null cx from the GC, via xml_mark => XMLArrayTrim. */
+static JSBool
+XMLArraySetCapacity(JSContext *cx, JSXMLArray *array, uint32 capacity)
+{
+ void **vector;
+
+ if (capacity == 0) {
+ /* We could let realloc(p, 0) free this, but purify gets confused. */
+ if (array->vector)
+ free(array->vector);
+ vector = NULL;
+ } else {
+ if ((size_t)capacity > ~(size_t)0 / sizeof(void *) ||
+ !(vector = (void **)
+ realloc(array->vector, capacity * sizeof(void *)))) {
+ if (cx)
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ }
+ array->capacity = JSXML_PRESET_CAPACITY | capacity;
+ array->vector = vector;
+ return JS_TRUE;
+}
+
+static void
+XMLArrayTrim(JSXMLArray *array)
+{
+ if (array->capacity & JSXML_PRESET_CAPACITY)
+ return;
+ if (array->length < array->capacity)
+ XMLArraySetCapacity(NULL, array, array->length);
+}
+
+static JSBool
+XMLArrayInit(JSContext *cx, JSXMLArray *array, uint32 capacity)
+{
+ array->length = array->capacity = 0;
+ array->vector = NULL;
+ array->cursors = NULL;
+ return capacity == 0 || XMLArraySetCapacity(cx, array, capacity);
+}
+
+static void
+XMLArrayFinish(JSContext *cx, JSXMLArray *array)
+{
+ JSXMLArrayCursor *cursor;
+
+ JS_free(cx, array->vector);
+
+ while ((cursor = array->cursors) != NULL)
+ XMLArrayCursorFinish(cursor);
+
+#ifdef DEBUG
+ memset(array, 0xd5, sizeof *array);
+#endif
+}
+
+#define XML_NOT_FOUND ((uint32) -1)
+
+static uint32
+XMLArrayFindMember(const JSXMLArray *array, void *elt, JSIdentityOp identity)
+{
+ void **vector;
+ uint32 i, n;
+
+ /* The identity op must not reallocate array->vector. */
+ vector = array->vector;
+ if (identity) {
+ for (i = 0, n = array->length; i < n; i++) {
+ if (identity(vector[i], elt))
+ return i;
+ }
+ } else {
+ for (i = 0, n = array->length; i < n; i++) {
+ if (vector[i] == elt)
+ return i;
+ }
+ }
+ return XML_NOT_FOUND;
+}
+
+/*
+ * Grow array vector capacity by powers of two to LINEAR_THRESHOLD, and after
+ * that, grow by LINEAR_INCREMENT. Both must be powers of two, and threshold
+ * should be greater than increment.
+ */
+#define LINEAR_THRESHOLD 256
+#define LINEAR_INCREMENT 32
+
+static JSBool
+XMLArrayAddMember(JSContext *cx, JSXMLArray *array, uint32 index, void *elt)
+{
+ uint32 capacity, i;
+ int log2;
+ void **vector;
+
+ if (index >= array->length) {
+ if (index >= JSXML_CAPACITY(array)) {
+ /* Arrange to clear JSXML_PRESET_CAPACITY from array->capacity. */
+ capacity = index + 1;
+ if (index >= LINEAR_THRESHOLD) {
+ capacity = JS_ROUNDUP(capacity, LINEAR_INCREMENT);
+ } else {
+ JS_CEILING_LOG2(log2, capacity);
+ capacity = JS_BIT(log2);
+ }
+ if ((size_t)capacity > ~(size_t)0 / sizeof(void *) ||
+ !(vector = (void **)
+ realloc(array->vector, capacity * sizeof(void *)))) {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+ array->capacity = capacity;
+ array->vector = vector;
+ for (i = array->length; i < index; i++)
+ vector[i] = NULL;
+ }
+ array->length = index + 1;
+ }
+
+ array->vector[index] = elt;
+ return JS_TRUE;
+}
+
+static JSBool
+XMLArrayInsert(JSContext *cx, JSXMLArray *array, uint32 i, uint32 n)
+{
+ uint32 j;
+ JSXMLArrayCursor *cursor;
+
+ j = array->length;
+ JS_ASSERT(i <= j);
+ if (!XMLArraySetCapacity(cx, array, j + n))
+ return JS_FALSE;
+
+ array->length = j + n;
+ JS_ASSERT(n != (uint32)-1);
+ while (j != i) {
+ --j;
+ array->vector[j + n] = array->vector[j];
+ }
+
+ for (cursor = array->cursors; cursor; cursor = cursor->next) {
+ if (cursor->index > i)
+ cursor->index += n;
+ }
+ return JS_TRUE;
+}
+
+static void *
+XMLArrayDelete(JSContext *cx, JSXMLArray *array, uint32 index, JSBool compress)
+{
+ uint32 length;
+ void **vector, *elt;
+ JSXMLArrayCursor *cursor;
+
+ length = array->length;
+ if (index >= length)
+ return NULL;
+
+ vector = array->vector;
+ elt = vector[index];
+ if (compress) {
+ while (++index < length)
+ vector[index-1] = vector[index];
+ array->length = length - 1;
+ array->capacity = JSXML_CAPACITY(array);
+ } else {
+ vector[index] = NULL;
+ }
+
+ for (cursor = array->cursors; cursor; cursor = cursor->next) {
+ if (cursor->index > index)
+ --cursor->index;
+ }
+ return elt;
+}
+
+static void
+XMLArrayTruncate(JSContext *cx, JSXMLArray *array, uint32 length)
+{
+ void **vector;
+
+ JS_ASSERT(!array->cursors);
+ if (length >= array->length)
+ return;
+
+ if (length == 0) {
+ if (array->vector)
+ free(array->vector);
+ vector = NULL;
+ } else {
+ vector = realloc(array->vector, length * sizeof(void *));
+ if (!vector)
+ return;
+ }
+
+ if (array->length > length)
+ array->length = length;
+ array->capacity = length;
+ array->vector = vector;
+}
+
+#define XMLARRAY_FIND_MEMBER(a,e,f) XMLArrayFindMember(a, (void *)(e), f)
+#define XMLARRAY_HAS_MEMBER(a,e,f) (XMLArrayFindMember(a, (void *)(e), f) != \
+ XML_NOT_FOUND)
+#define XMLARRAY_MEMBER(a,i,t) (((i) < (a)->length) \
+ ? (t *) (a)->vector[i] \
+ : NULL)
+#define XMLARRAY_SET_MEMBER(a,i,e) JS_BEGIN_MACRO \
+ if ((a)->length <= (i)) \
+ (a)->length = (i) + 1; \
+ ((a)->vector[i] = (void *)(e)); \
+ JS_END_MACRO
+#define XMLARRAY_ADD_MEMBER(x,a,i,e)XMLArrayAddMember(x, a, i, (void *)(e))
+#define XMLARRAY_INSERT(x,a,i,n) XMLArrayInsert(x, a, i, n)
+#define XMLARRAY_APPEND(x,a,e) XMLARRAY_ADD_MEMBER(x, a, (a)->length, (e))
+#define XMLARRAY_DELETE(x,a,i,c,t) ((t *) XMLArrayDelete(x, a, i, c))
+#define XMLARRAY_TRUNCATE(x,a,n) XMLArrayTruncate(x, a, n)
+
+/*
+ * Define XML setting property strings and constants early, so everyone can
+ * use the same names and their magic numbers (tinyids, flags).
+ */
+static const char js_ignoreComments_str[] = "ignoreComments";
+static const char js_ignoreProcessingInstructions_str[]
+ = "ignoreProcessingInstructions";
+static const char js_ignoreWhitespace_str[] = "ignoreWhitespace";
+static const char js_prettyPrinting_str[] = "prettyPrinting";
+static const char js_prettyIndent_str[] = "prettyIndent";
+
+/*
+ * NB: These XML static property tinyids must
+ * (a) not collide with the generic negative tinyids at the top of jsfun.c;
+ * (b) index their corresponding xml_static_props array elements.
+ * Don't change 'em!
+ */
+enum xml_static_tinyid {
+ XML_IGNORE_COMMENTS,
+ XML_IGNORE_PROCESSING_INSTRUCTIONS,
+ XML_IGNORE_WHITESPACE,
+ XML_PRETTY_PRINTING,
+ XML_PRETTY_INDENT
+};
+
+static JSBool
+xml_setting_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ return JS_TRUE;
+}
+
+static JSBool
+xml_setting_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSBool b;
+ uint8 flag;
+
+ JS_ASSERT(JSVAL_IS_INT(id));
+ if (!js_ValueToBoolean(cx, *vp, &b))
+ return JS_FALSE;
+
+ flag = JS_BIT(JSVAL_TO_INT(id));
+ if (b)
+ cx->xmlSettingFlags |= flag;
+ else
+ cx->xmlSettingFlags &= ~flag;
+ return JS_TRUE;
+}
+
+static JSPropertySpec xml_static_props[] = {
+ {js_ignoreComments_str, XML_IGNORE_COMMENTS, JSPROP_PERMANENT,
+ xml_setting_getter, xml_setting_setter},
+ {js_ignoreProcessingInstructions_str,
+ XML_IGNORE_PROCESSING_INSTRUCTIONS, JSPROP_PERMANENT,
+ xml_setting_getter, xml_setting_setter},
+ {js_ignoreWhitespace_str, XML_IGNORE_WHITESPACE, JSPROP_PERMANENT,
+ xml_setting_getter, xml_setting_setter},
+ {js_prettyPrinting_str, XML_PRETTY_PRINTING, JSPROP_PERMANENT,
+ xml_setting_getter, xml_setting_setter},
+ {js_prettyIndent_str, XML_PRETTY_INDENT, JSPROP_PERMANENT,
+ xml_setting_getter, NULL},
+ {0,0,0,0,0}
+};
+
+/* Derive cx->xmlSettingFlags bits from xml_static_props tinyids. */
+#define XSF_IGNORE_COMMENTS JS_BIT(XML_IGNORE_COMMENTS)
+#define XSF_IGNORE_PROCESSING_INSTRUCTIONS \
+ JS_BIT(XML_IGNORE_PROCESSING_INSTRUCTIONS)
+#define XSF_IGNORE_WHITESPACE JS_BIT(XML_IGNORE_WHITESPACE)
+#define XSF_PRETTY_PRINTING JS_BIT(XML_PRETTY_PRINTING)
+#define XSF_CACHE_VALID JS_BIT(XML_PRETTY_INDENT)
+
+/*
+ * Extra, unrelated but necessarily disjoint flag used by ParseNodeToXML.
+ * This flag means a couple of things:
+ *
+ * - The top JSXML created for a parse tree must have an object owning it.
+ *
+ * - That the default namespace normally inherited from the temporary
+ * <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, "
");
+ else if (c == '\r')
+ js_AppendCString(sb, "
");
+ else if (c == '\t')
+ js_AppendCString(sb, "	");
+ else
+ js_AppendChar(sb, c);
+ }
+ JS_ASSERT(STRING_BUFFER_OK(sb));
+ str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb), 0);
+ if (!str)
+ js_FinishStringBuffer(sb);
+ }
+ return str;
+}
+
+/* 13.3.5.4 [[GetNamespace]]([InScopeNamespaces]) */
+static JSXMLNamespace *
+GetNamespace(JSContext *cx, JSXMLQName *qn, const JSXMLArray *inScopeNSes)
+{
+ JSXMLNamespace *match, *ns;
+ uint32 i, n;
+ jsval argv[2];
+ JSObject *nsobj;
+
+ JS_ASSERT(qn->uri);
+ if (!qn->uri) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_XML_NAMESPACE,
+ qn->prefix
+ ? js_ValueToPrintableString(cx,
+ STRING_TO_JSVAL(qn->prefix))
+ : js_type_str[JSTYPE_VOID]);
+ return NULL;
+ }
+
+ /* Look for a matching namespace in inScopeNSes, if provided. */
+ match = NULL;
+ if (inScopeNSes) {
+ for (i = 0, n = inScopeNSes->length; i < n; i++) {
+ ns = XMLARRAY_MEMBER(inScopeNSes, i, JSXMLNamespace);
+ if (!ns)
+ continue;
+
+ /*
+ * Erratum, very tricky, and not specified in ECMA-357 13.3.5.4:
+ * If we preserve prefixes, we must match null qn->prefix against
+ * an empty ns->prefix, in order to avoid generating redundant
+ * prefixed and default namespaces for cases such as:
+ *
+ * x = <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 = ∅
+ }
+ 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, ©->xml_kids, copy, flags);
+ if (!ok)
+ goto out;
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ copy->xml_target = xml->xml_target;
+ copy->xml_targetprop = xml->xml_targetprop;
+ } else {
+ n = xml->xml_namespaces.length;
+ ok = XMLArraySetCapacity(cx, ©->xml_namespaces, n);
+ if (!ok)
+ goto out;
+ for (i = 0; i < n; i++) {
+ ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace);
+ if (!ns)
+ continue;
+ ns2 = js_NewXMLNamespace(cx, ns->prefix, ns->uri, ns->declared);
+ if (!ns2) {
+ copy->xml_namespaces.length = i;
+ ok = JS_FALSE;
+ goto out;
+ }
+ XMLARRAY_SET_MEMBER(©->xml_namespaces, i, ns2);
+ }
+
+ ok = DeepCopySetInLRS(cx, &xml->xml_attrs, ©->xml_attrs, copy,
+ 0);
+ if (!ok)
+ goto out;
+ }
+ }
+
+out:
+ if (!ok)
+ return NULL;
+ return copy;
+}
+
+static void
+ReportBadXMLName(JSContext *cx, jsval id)
+{
+ JSString *name;
+
+ name = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, id, NULL);
+ if (name) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_XML_NAME,
+ JS_GetStringBytes(name));
+ }
+}
+
+/* ECMA-357 9.1.1.4 XML [[DeleteByIndex]]. */
+static JSBool
+DeleteByIndex(JSContext *cx, JSXML *xml, jsval id, jsval *vp)
+{
+ uint32 index;
+ JSXML *kid;
+
+ if (!js_IdIsIndex(id, &index)) {
+ ReportBadXMLName(cx, id);
+ return JS_FALSE;
+ }
+
+ if (JSXML_HAS_KIDS(xml) && index < xml->xml_kids.length) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML);
+ if (kid)
+ kid->parent = NULL;
+ XMLArrayDelete(cx, &xml->xml_kids, index, JS_TRUE);
+ }
+
+ *vp = JSVAL_TRUE;
+ return JS_TRUE;
+}
+
+typedef JSBool (*JSXMLNameMatcher)(JSXMLQName *nameqn, JSXML *xml);
+
+static JSBool
+MatchAttrName(JSXMLQName *nameqn, JSXML *attr)
+{
+ JSXMLQName *attrqn = attr->name;
+
+ return (IS_STAR(nameqn->localName) ||
+ !js_CompareStrings(attrqn->localName, nameqn->localName)) &&
+ (!nameqn->uri ||
+ !js_CompareStrings(attrqn->uri, nameqn->uri));
+}
+
+static JSBool
+MatchElemName(JSXMLQName *nameqn, JSXML *elem)
+{
+ return (IS_STAR(nameqn->localName) ||
+ (elem->xml_class == JSXML_CLASS_ELEMENT &&
+ !js_CompareStrings(elem->name->localName, nameqn->localName))) &&
+ (!nameqn->uri ||
+ (elem->xml_class == JSXML_CLASS_ELEMENT &&
+ !js_CompareStrings(elem->name->uri, nameqn->uri)));
+}
+
+/* ECMA-357 9.1.1.8 XML [[Descendants]] and 9.2.1.8 XMLList [[Descendants]]. */
+static JSBool
+DescendantsHelper(JSContext *cx, JSXML *xml, JSXMLQName *nameqn, JSXML *list)
+{
+ uint32 i, n;
+ JSXML *attr, *kid;
+
+ if (xml->xml_class == JSXML_CLASS_ELEMENT &&
+ OBJ_GET_CLASS(cx, nameqn->object) == &js_AttributeNameClass) {
+ for (i = 0, n = xml->xml_attrs.length; i < n; i++) {
+ attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML);
+ if (attr && MatchAttrName(nameqn, attr)) {
+ if (!Append(cx, list, attr))
+ return JS_FALSE;
+ }
+ }
+ }
+
+ for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (!kid)
+ continue;
+ if (OBJ_GET_CLASS(cx, nameqn->object) != &js_AttributeNameClass &&
+ MatchElemName(nameqn, kid)) {
+ if (!Append(cx, list, kid))
+ return JS_FALSE;
+ }
+ if (!DescendantsHelper(cx, kid, nameqn, list))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+static JSXML *
+Descendants(JSContext *cx, JSXML *xml, jsval id)
+{
+ jsid funid;
+ JSXMLQName *nameqn;
+ JSObject *listobj;
+ JSXML *list, *kid;
+ uint32 i, n;
+ JSBool ok;
+
+ nameqn = ToXMLName(cx, id, &funid);
+ if (!nameqn)
+ return NULL;
+
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ return NULL;
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ if (funid)
+ return list;
+
+ /*
+ * Protect nameqn's object and strings from GC by linking list to it
+ * temporarily. The cx->newborn[GCX_OBJECT] GC root protects listobj,
+ * which protects list. Any other object allocations occuring beneath
+ * DescendantsHelper use local roots.
+ */
+ list->name = nameqn;
+ if (!JS_EnterLocalRootScope(cx))
+ return NULL;
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ ok = JS_TRUE;
+ for (i = 0, n = xml->xml_kids.length; i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) {
+ ok = DescendantsHelper(cx, kid, nameqn, list);
+ if (!ok)
+ break;
+ }
+ }
+ } else {
+ ok = DescendantsHelper(cx, xml, nameqn, list);
+ }
+ JS_LeaveLocalRootScope(cx);
+ if (!ok)
+ return NULL;
+ list->name = NULL;
+ return list;
+}
+
+static JSBool
+xml_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
+
+/* Recursive (JSXML *) parameterized version of Equals. */
+static JSBool
+XMLEquals(JSContext *cx, JSXML *xml, JSXML *vxml, JSBool *bp)
+{
+ JSXMLQName *qn, *vqn;
+ uint32 i, j, n;
+ JSXMLArrayCursor cursor, vcursor;
+ JSXML *kid, *vkid, *attr, *vattr;
+ JSBool ok;
+ JSObject *xobj, *vobj;
+
+retry:
+ if (xml->xml_class != vxml->xml_class) {
+ if (xml->xml_class == JSXML_CLASS_LIST && xml->xml_kids.length == 1) {
+ xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
+ if (xml)
+ goto retry;
+ }
+ if (vxml->xml_class == JSXML_CLASS_LIST && vxml->xml_kids.length == 1) {
+ vxml = XMLARRAY_MEMBER(&vxml->xml_kids, 0, JSXML);
+ if (vxml)
+ goto retry;
+ }
+ *bp = JS_FALSE;
+ return JS_TRUE;
+ }
+
+ qn = xml->name;
+ vqn = vxml->name;
+ if (qn) {
+ *bp = vqn &&
+ !js_CompareStrings(qn->localName, vqn->localName) &&
+ !js_CompareStrings(qn->uri, vqn->uri);
+ } else {
+ *bp = vqn == NULL;
+ }
+ if (!*bp)
+ return JS_TRUE;
+
+ if (JSXML_HAS_VALUE(xml)) {
+ *bp = !js_CompareStrings(xml->xml_value, vxml->xml_value);
+ } else if (xml->xml_kids.length != vxml->xml_kids.length) {
+ *bp = JS_FALSE;
+ } else {
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ XMLArrayCursorInit(&vcursor, &vxml->xml_kids);
+ for (;;) {
+ kid = (JSXML *) XMLArrayCursorNext(&cursor);
+ vkid = (JSXML *) XMLArrayCursorNext(&vcursor);
+ if (!kid || !vkid) {
+ *bp = !kid && !vkid;
+ ok = JS_TRUE;
+ break;
+ }
+ xobj = js_GetXMLObject(cx, kid);
+ vobj = js_GetXMLObject(cx, vkid);
+ ok = xobj && vobj &&
+ xml_equality(cx, xobj, OBJECT_TO_JSVAL(vobj), bp);
+ if (!ok || !*bp)
+ break;
+ }
+ XMLArrayCursorFinish(&vcursor);
+ XMLArrayCursorFinish(&cursor);
+ if (!ok)
+ return JS_FALSE;
+
+ if (*bp && xml->xml_class == JSXML_CLASS_ELEMENT) {
+ n = xml->xml_attrs.length;
+ if (n != vxml->xml_attrs.length)
+ *bp = JS_FALSE;
+ for (i = 0; *bp && i < n; i++) {
+ attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML);
+ if (!attr)
+ continue;
+ j = XMLARRAY_FIND_MEMBER(&vxml->xml_attrs, attr, attr_identity);
+ if (j == XML_NOT_FOUND) {
+ *bp = JS_FALSE;
+ break;
+ }
+ vattr = XMLARRAY_MEMBER(&vxml->xml_attrs, j, JSXML);
+ if (!vattr)
+ continue;
+ *bp = !js_CompareStrings(attr->xml_value, vattr->xml_value);
+ }
+ }
+ }
+
+ return JS_TRUE;
+}
+
+/* ECMA-357 9.1.1.9 XML [[Equals]] and 9.2.1.9 XMLList [[Equals]]. */
+static JSBool
+Equals(JSContext *cx, JSXML *xml, jsval v, JSBool *bp)
+{
+ JSObject *vobj;
+ JSXML *vxml;
+
+ if (JSVAL_IS_PRIMITIVE(v)) {
+ *bp = JS_FALSE;
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ if (xml->xml_kids.length == 1) {
+ vxml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
+ if (!vxml)
+ return JS_TRUE;
+ vobj = js_GetXMLObject(cx, vxml);
+ if (!vobj)
+ return JS_FALSE;
+ return js_XMLObjectOps.equality(cx, vobj, v, bp);
+ }
+ if (JSVAL_IS_VOID(v) && xml->xml_kids.length == 0)
+ *bp = JS_TRUE;
+ }
+ } else {
+ vobj = JSVAL_TO_OBJECT(v);
+ if (!OBJECT_IS_XML(cx, vobj)) {
+ *bp = JS_FALSE;
+ } else {
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ if (!XMLEquals(cx, xml, vxml, bp))
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+CheckCycle(JSContext *cx, JSXML *xml, JSXML *kid)
+{
+ JS_ASSERT(kid->xml_class != JSXML_CLASS_LIST);
+
+ do {
+ if (xml == kid) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CYCLIC_VALUE, js_XML_str);
+ return JS_FALSE;
+ }
+ } while ((xml = xml->parent) != NULL);
+
+ return JS_TRUE;
+}
+
+/* ECMA-357 9.1.1.11 XML [[Insert]]. */
+static JSBool
+Insert(JSContext *cx, JSXML *xml, uint32 i, jsval v)
+{
+ uint32 j, n;
+ JSXML *vxml, *kid;
+ JSObject *vobj;
+ JSString *str;
+
+ if (!JSXML_HAS_KIDS(xml))
+ return JS_TRUE;
+
+ n = 1;
+ vxml = NULL;
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ vobj = JSVAL_TO_OBJECT(v);
+ if (OBJECT_IS_XML(cx, vobj)) {
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ if (vxml->xml_class == JSXML_CLASS_LIST) {
+ n = vxml->xml_kids.length;
+ if (n == 0)
+ return JS_TRUE;
+ for (j = 0; j < n; j++) {
+ kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML);
+ if (!kid)
+ continue;
+ if (!CheckCycle(cx, xml, kid))
+ return JS_FALSE;
+ }
+ } else if (vxml->xml_class == JSXML_CLASS_ELEMENT) {
+ /* OPTION: enforce that descendants have superset namespaces. */
+ if (!CheckCycle(cx, xml, vxml))
+ return JS_FALSE;
+ }
+ }
+ }
+ if (!vxml) {
+ str = js_ValueToString(cx, v);
+ if (!str)
+ return JS_FALSE;
+
+ vxml = js_NewXML(cx, JSXML_CLASS_TEXT);
+ if (!vxml)
+ return JS_FALSE;
+ vxml->xml_value = str;
+ }
+
+ if (i > xml->xml_kids.length)
+ i = xml->xml_kids.length;
+
+ if (!XMLArrayInsert(cx, &xml->xml_kids, i, n))
+ return JS_FALSE;
+
+ if (vxml->xml_class == JSXML_CLASS_LIST) {
+ for (j = 0; j < n; j++) {
+ kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML);
+ if (!kid)
+ continue;
+ kid->parent = xml;
+ XMLARRAY_SET_MEMBER(&xml->xml_kids, i + j, kid);
+
+ /* OPTION: enforce that descendants have superset namespaces. */
+ }
+ } else {
+ vxml->parent = xml;
+ XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+IndexToIdVal(JSContext *cx, uint32 index, jsval *idvp)
+{
+ JSString *str;
+
+ if (index <= JSVAL_INT_MAX) {
+ *idvp = INT_TO_JSVAL(index);
+ } else {
+ str = js_NumberToString(cx, (jsdouble) index);
+ if (!str)
+ return JS_FALSE;
+ *idvp = STRING_TO_JSVAL(str);
+ }
+ return JS_TRUE;
+}
+
+/* ECMA-357 9.1.1.12 XML [[Replace]]. */
+static JSBool
+Replace(JSContext *cx, JSXML *xml, jsval id, jsval v)
+{
+ uint32 i, n;
+ JSXML *vxml, *kid;
+ JSObject *vobj;
+ jsval junk;
+ JSString *str;
+
+ if (!JSXML_HAS_KIDS(xml))
+ return JS_TRUE;
+
+ if (!js_IdIsIndex(id, &i)) {
+ ReportBadXMLName(cx, id);
+ return JS_FALSE;
+ }
+
+ /*
+ * 9.1.1.12
+ * [[Replace]] handles _i >= x.[[Length]]_ by incrementing _x.[[Length]_.
+ * It should therefore constrain callers to pass in _i <= x.[[Length]]_.
+ */
+ n = xml->xml_kids.length;
+ if (i >= n) {
+ if (!IndexToIdVal(cx, n, &id))
+ return JS_FALSE;
+ i = n;
+ }
+
+ vxml = NULL;
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ vobj = JSVAL_TO_OBJECT(v);
+ if (OBJECT_IS_XML(cx, vobj))
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ }
+
+ switch (vxml ? vxml->xml_class : JSXML_CLASS_LIMIT) {
+ case JSXML_CLASS_ELEMENT:
+ /* OPTION: enforce that descendants have superset namespaces. */
+ if (!CheckCycle(cx, xml, vxml))
+ return JS_FALSE;
+ case JSXML_CLASS_COMMENT:
+ case JSXML_CLASS_PROCESSING_INSTRUCTION:
+ case JSXML_CLASS_TEXT:
+ goto do_replace;
+
+ case JSXML_CLASS_LIST:
+ if (i < n && !DeleteByIndex(cx, xml, id, &junk))
+ return JS_FALSE;
+ if (!Insert(cx, xml, i, v))
+ return JS_FALSE;
+ break;
+
+ default:
+ str = js_ValueToString(cx, v);
+ if (!str)
+ return JS_FALSE;
+
+ vxml = js_NewXML(cx, JSXML_CLASS_TEXT);
+ if (!vxml)
+ return JS_FALSE;
+ vxml->xml_value = str;
+
+ do_replace:
+ vxml->parent = xml;
+ if (i < n) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid)
+ kid->parent = NULL;
+ }
+ if (!XMLARRAY_ADD_MEMBER(cx, &xml->xml_kids, i, vxml))
+ return JS_FALSE;
+ break;
+ }
+
+ return JS_TRUE;
+}
+
+/* Forward declared -- its implementation uses other statics that call it. */
+static JSBool
+ResolveValue(JSContext *cx, JSXML *list, JSXML **result);
+
+/* ECMA-357 9.1.1.3 XML [[Delete]], 9.2.1.3 XML [[Delete]]. */
+static JSBool
+DeleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSXML *xml, *kid, *parent;
+ JSBool isIndex;
+ JSXMLArray *array;
+ uint32 length, index, deleteCount;
+ JSXMLQName *nameqn;
+ jsid funid;
+ JSObject *nameobj, *kidobj;
+ JSXMLNameMatcher matcher;
+
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ isIndex = js_IdIsIndex(id, &index);
+ if (JSXML_HAS_KIDS(xml)) {
+ array = &xml->xml_kids;
+ length = array->length;
+ } else {
+ array = NULL;
+ length = 0;
+ }
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* ECMA-357 9.2.1.3. */
+ if (isIndex && index < length) {
+ kid = XMLARRAY_MEMBER(array, index, JSXML);
+ if (!kid)
+ goto out;
+ parent = kid->parent;
+ if (parent) {
+ JS_ASSERT(parent != xml);
+ JS_ASSERT(JSXML_HAS_KIDS(parent));
+
+ if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) {
+ nameqn = kid->name;
+ nameobj = js_GetAttributeNameObject(cx, nameqn);
+ if (!nameobj || !js_GetXMLObject(cx, parent))
+ return JS_FALSE;
+
+ id = OBJECT_TO_JSVAL(nameobj);
+ if (!DeleteProperty(cx, parent->object, id, vp))
+ return JS_FALSE;
+ } else {
+ index = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL);
+ JS_ASSERT(index != XML_NOT_FOUND);
+ if (!IndexToIdVal(cx, index, &id))
+ return JS_FALSE;
+ if (!DeleteByIndex(cx, parent, id, vp))
+ return JS_FALSE;
+ }
+ }
+
+ XMLArrayDelete(cx, array, index, JS_TRUE);
+ } else {
+ for (index = 0; index < length; index++) {
+ kid = XMLARRAY_MEMBER(array, index, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj || !DeleteProperty(cx, kidobj, id, vp))
+ return JS_FALSE;
+ }
+ }
+ }
+ } else {
+ /* ECMA-357 9.1.1.3. */
+ if (isIndex) {
+ /* See NOTE in spec: this variation is reserved for future use. */
+ ReportBadXMLName(cx, id);
+ return JS_FALSE;
+ }
+
+ nameqn = ToXMLName(cx, id, &funid);
+ if (!nameqn)
+ return JS_FALSE;
+ if (funid)
+ goto out;
+ nameobj = nameqn->object;
+
+ if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) {
+ if (xml->xml_class != JSXML_CLASS_ELEMENT)
+ goto out;
+ array = &xml->xml_attrs;
+ length = array->length;
+ matcher = MatchAttrName;
+ } else {
+ matcher = MatchElemName;
+ }
+ if (length != 0) {
+ deleteCount = 0;
+ for (index = 0; index < length; index++) {
+ kid = XMLARRAY_MEMBER(array, index, JSXML);
+ if (kid && matcher(nameqn, kid)) {
+ kid->parent = NULL;
+ XMLArrayDelete(cx, array, index, JS_FALSE);
+ ++deleteCount;
+ } else if (deleteCount != 0) {
+ XMLARRAY_SET_MEMBER(array,
+ index - deleteCount,
+ array->vector[index]);
+ }
+ }
+ array->length -= deleteCount;
+ }
+ }
+
+out:
+ *vp = JSVAL_TRUE;
+ return JS_TRUE;
+}
+
+/*
+ * Class compatibility mask flag bits stored in xml_methods[i].extra. If XML
+ * and XMLList are unified (an incompatible change to ECMA-357), then we don't
+ * need any of this.
+ */
+#define XML_MASK 0x1
+#define XMLLIST_MASK 0x2
+#define GENERIC_MASK (XML_MASK | XMLLIST_MASK)
+#define CLASS_TO_MASK(c) (1 + ((c) == JSXML_CLASS_LIST))
+
+static JSBool
+GetFunction(JSContext *cx, JSObject *obj, JSXML *xml, jsid id, jsval *vp)
+{
+ JSFunction *fun;
+
+ do {
+ /* XXXbe really want a separate scope for function::*. */
+ if (!js_GetProperty(cx, obj, id, vp))
+ return JS_FALSE;
+ if (JSVAL_IS_FUNCTION(cx, *vp)) {
+ if (xml && OBJECT_IS_XML(cx, obj)) {
+ fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(*vp));
+ if (fun->spare &&
+ (fun->spare & CLASS_TO_MASK(xml->xml_class)) == 0) {
+ /* XML method called on XMLList or vice versa. */
+ *vp = JSVAL_VOID;
+ }
+ }
+ break;
+ }
+ } while ((obj = OBJ_GET_PROTO(cx, obj)) != NULL);
+ return JS_TRUE;
+}
+
+static JSBool
+SyncInScopeNamespaces(JSContext *cx, JSXML *xml)
+{
+ JSXMLArray *nsarray;
+ uint32 i, n;
+ JSXMLNamespace *ns;
+
+ nsarray = &xml->xml_namespaces;
+ while ((xml = xml->parent) != NULL) {
+ for (i = 0, n = xml->xml_namespaces.length; i < n; i++) {
+ ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace);
+ if (ns && !XMLARRAY_HAS_MEMBER(nsarray, ns, namespace_identity)) {
+ if (!XMLARRAY_APPEND(cx, nsarray, ns))
+ return JS_FALSE;
+ }
+ }
+ }
+ return JS_TRUE;
+}
+
+/* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */
+static JSBool
+GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSXML *xml, *list, *kid;
+ uint32 index;
+ JSObject *kidobj, *listobj, *nameobj;
+ JSXMLQName *nameqn;
+ jsid funid;
+ JSBool ok;
+ JSXMLArrayCursor cursor;
+ jsval kidval;
+ JSXMLArray *array;
+ JSXMLNameMatcher matcher;
+
+ xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
+ if (!xml)
+ return JS_TRUE;
+
+#ifdef __GNUC__
+ list = NULL; /* quell GCC overwarning */
+#endif
+
+retry:
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* ECMA-357 9.2.1.1 starts here. */
+ if (js_IdIsIndex(id, &index)) {
+ /*
+ * Erratum: 9.2 is not completely clear that indexed properties
+ * correspond to kids, but that's what it seems to say, and it's
+ * what any sane user would want.
+ */
+ if (index < xml->xml_kids.length) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML);
+ if (!kid) {
+ *vp = JSVAL_VOID;
+ return JS_TRUE;
+ }
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ return JS_FALSE;
+
+ *vp = OBJECT_TO_JSVAL(kidobj);
+ } else {
+ *vp = JSVAL_VOID;
+ }
+ return JS_TRUE;
+ }
+
+ nameqn = ToXMLName(cx, id, &funid);
+ if (!nameqn)
+ return JS_FALSE;
+ if (funid)
+ return GetFunction(cx, obj, xml, funid, vp);
+
+ /*
+ * Recursion through GetProperty may allocate more list objects, so
+ * we make use of local root scopes here. Each new allocation will
+ * push the newborn onto the local root stack.
+ */
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ return JS_FALSE;
+
+ /*
+ * NB: nameqn is already protected from GC by cx->newborn[GCX_OBJECT]
+ * until listobj is created. After that, a local root keeps listobj
+ * alive, and listobj's private keeps nameqn alive via targetprop.
+ */
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj) {
+ ok = JS_FALSE;
+ } else {
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ list->xml_target = xml;
+
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ if (kid->xml_class == JSXML_CLASS_ELEMENT) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj) {
+ ok = JS_FALSE;
+ break;
+ }
+ ok = GetProperty(cx, kidobj, id, &kidval);
+ if (!ok)
+ break;
+ kidobj = JSVAL_TO_OBJECT(kidval);
+ kid = (JSXML *) JS_GetPrivate(cx, kidobj);
+ if (JSXML_LENGTH(kid) > 0) {
+ ok = Append(cx, list, kid);
+ if (!ok)
+ break;
+ }
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ }
+ } else {
+ /* ECMA-357 9.1.1.1 starts here. */
+ if (js_IdIsIndex(id, &index)) {
+ obj = ToXMLList(cx, OBJECT_TO_JSVAL(obj));
+ if (!obj)
+ return JS_FALSE;
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ goto retry;
+ }
+
+ nameqn = ToXMLName(cx, id, &funid);
+ if (!nameqn)
+ return JS_FALSE;
+ if (funid)
+ return GetFunction(cx, obj, xml, funid, vp);
+ nameobj = nameqn->object;
+
+ /*
+ * Recursion through GetProperty may allocate more list objects, so
+ * we make use of local root scopes here. Each new allocation will
+ * push the newborn onto the local root stack.
+ */
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ return JS_FALSE;
+
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj) {
+ ok = JS_FALSE;
+ } else {
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ list->xml_target = xml;
+
+ if (JSXML_HAS_KIDS(xml)) {
+ if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) {
+ array = &xml->xml_attrs;
+ matcher = MatchAttrName;
+ } else {
+ array = &xml->xml_kids;
+ matcher = MatchElemName;
+ }
+ XMLArrayCursorInit(&cursor, array);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ if (matcher(nameqn, kid)) {
+ if (array == &xml->xml_kids &&
+ kid->xml_class == JSXML_CLASS_ELEMENT) {
+ ok = SyncInScopeNamespaces(cx, kid);
+ if (!ok)
+ break;
+ }
+ ok = Append(cx, list, kid);
+ if (!ok)
+ break;
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ }
+ }
+ }
+
+ /* Common tail code for list and non-list cases. */
+ JS_LeaveLocalRootScope(cx);
+ if (!ok)
+ return JS_FALSE;
+
+ /*
+ * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the given list's
+ * [[TargetProperty]] to the property that is being appended. This means
+ * that any use of the internal [[Get]] property returns a list which,
+ * when used by e.g. [[Insert]] duplicates the last element matched by id.
+ * See bug 336921.
+ */
+ list->xml_targetprop = nameqn;
+ *vp = OBJECT_TO_JSVAL(listobj);
+ return JS_TRUE;
+}
+
+static JSXML *
+CopyOnWrite(JSContext *cx, JSXML *xml, JSObject *obj)
+{
+ JS_ASSERT(xml->object != obj);
+
+ xml = DeepCopy(cx, xml, obj, 0);
+ if (!xml)
+ return NULL;
+
+ JS_ASSERT(xml->object == obj);
+ return xml;
+}
+
+#define CHECK_COPY_ON_WRITE(cx,xml,obj) \
+ (xml->object == obj ? xml : CopyOnWrite(cx, xml, obj))
+
+static JSString *
+KidToString(JSContext *cx, JSXML *xml, uint32 index)
+{
+ JSXML *kid;
+ JSObject *kidobj;
+
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML);
+ if (!kid)
+ return cx->runtime->emptyString;
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ return NULL;
+ return js_ValueToString(cx, OBJECT_TO_JSVAL(kidobj));
+}
+
+/* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */
+static JSBool
+PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSBool ok, primitiveAssign;
+ enum { OBJ_ROOT, ID_ROOT, VAL_ROOT };
+ jsval roots[3];
+ JSTempValueRooter tvr;
+ JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match;
+ JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj;
+ JSXMLQName *targetprop, *nameqn, *attrqn;
+ uint32 index, i, j, k, n, q;
+ jsval attrval, nsval, junk;
+ jsid funid;
+ JSString *left, *right, *space;
+ JSXMLNamespace *ns;
+
+ xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
+ if (!xml)
+ return JS_TRUE;
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+
+ /* Precompute vxml for 9.2.1.2 2(c)(vii)(2-3) and 2(d) and 9.1.1.2 1. */
+ vxml = NULL;
+ if (!JSVAL_IS_PRIMITIVE(*vp)) {
+ vobj = JSVAL_TO_OBJECT(*vp);
+ if (OBJECT_IS_XML(cx, vobj))
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ }
+
+ /* Control flow after here must exit via label out. */
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ return JS_FALSE;
+ roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj);
+ roots[ID_ROOT] = id;
+ roots[VAL_ROOT] = *vp;
+ JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr);
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* ECMA-357 9.2.1.2. */
+ if (js_IdIsIndex(id, &index)) {
+ /* Step 1 sets i to the property index. */
+ i = index;
+
+ /* 2(a-b). */
+ if (xml->xml_target) {
+ ok = ResolveValue(cx, xml->xml_target, &rxml);
+ if (!ok)
+ goto out;
+ if (!rxml)
+ goto out;
+ JS_ASSERT(rxml->object);
+ } else {
+ rxml = NULL;
+ }
+
+ /* 2(c). */
+ if (index >= xml->xml_kids.length) {
+ /* 2(c)(i). */
+ if (rxml) {
+ if (rxml->xml_class == JSXML_CLASS_LIST) {
+ if (rxml->xml_kids.length != 1)
+ goto out;
+ rxml = XMLARRAY_MEMBER(&rxml->xml_kids, 0, JSXML);
+ if (!rxml)
+ goto out;
+ ok = js_GetXMLObject(cx, rxml) != NULL;
+ if (!ok)
+ goto out;
+ }
+
+ /*
+ * Erratum: ECMA-357 9.2.1.2 step 2(c)(ii) sets
+ * _y.[[Parent]] = r_ where _r_ is the result of
+ * [[ResolveValue]] called on _x.[[TargetObject]] in
+ * 2(a)(i). This can result in text parenting text:
+ *
+ * var MYXML = new XML();
+ * MYXML.appendChild(new XML("<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, ©->xml_kids, n);
+ if (!ok)
+ goto out;
+ for (k = 0; k < n; k++) {
+ kid2 = XMLARRAY_MEMBER(&vxml->xml_kids, k, JSXML);
+ XMLARRAY_SET_MEMBER(©->xml_kids, k, kid2);
+ }
+
+ JS_ASSERT(parent != xml);
+ if (parent) {
+ q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL);
+ JS_ASSERT(q != XML_NOT_FOUND);
+
+ ok = IndexToIdVal(cx, q, &id);
+ if (!ok)
+ goto out;
+ ok = Replace(cx, parent, id, OBJECT_TO_JSVAL(copyobj));
+ if (!ok)
+ goto out;
+
+#ifdef DEBUG
+ /* Erratum: this loop in the spec is useless. */
+ for (j = 0, n = copy->xml_kids.length; j < n; j++) {
+ kid2 = XMLARRAY_MEMBER(&parent->xml_kids, q + j, JSXML);
+ JS_ASSERT(XMLARRAY_MEMBER(©->xml_kids, j, JSXML)
+ == kid2);
+ }
+#endif
+ }
+
+ /*
+ * 2(f)(iv-vi).
+ * Erratum: notice the unhandled zero-length V basis case and
+ * the off-by-one errors for the n != 0 cases in the spec.
+ */
+ if (n == 0) {
+ XMLArrayDelete(cx, &xml->xml_kids, i, JS_TRUE);
+ } else {
+ ok = XMLArrayInsert(cx, &xml->xml_kids, i + 1, n - 1);
+ if (!ok)
+ goto out;
+
+ for (j = 0; j < n; j++)
+ xml->xml_kids.vector[i + j] = copy->xml_kids.vector[j];
+ }
+ }
+
+ /* 2(g). */
+ else if (vxml || JSXML_HAS_VALUE(kid)) {
+ if (parent) {
+ q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL);
+ JS_ASSERT(q != XML_NOT_FOUND);
+
+ ok = IndexToIdVal(cx, q, &id);
+ if (!ok)
+ goto out;
+ ok = Replace(cx, parent, id, *vp);
+ if (!ok)
+ goto out;
+
+ vxml = XMLARRAY_MEMBER(&parent->xml_kids, q, JSXML);
+ if (!vxml)
+ goto out;
+ roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vxml->object);
+ }
+
+ /*
+ * 2(g)(iii).
+ * Erratum: _V_ may not be of type XML, but all index-named
+ * properties _x[i]_ in an XMLList _x_ must be of type XML,
+ * according to 9.2.1.1 Overview and other places in the spec.
+ *
+ * Thanks to 2(d), we know _V_ (*vp here) is either a string
+ * or an XML/XMLList object. If *vp is a string, call ToXML
+ * on it to satisfy the constraint.
+ */
+ if (!vxml) {
+ JS_ASSERT(JSVAL_IS_STRING(*vp));
+ vobj = ToXML(cx, *vp);
+ if (!vobj)
+ goto bad;
+ roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vobj);
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ }
+ XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml);
+ }
+
+ /* 2(h). */
+ else {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ goto bad;
+ id = ATOM_KEY(cx->runtime->atomState.starAtom);
+ ok = PutProperty(cx, kidobj, id, vp);
+ if (!ok)
+ goto out;
+ }
+ } else {
+ /*
+ * 3.
+ * Erratum: if x.[[Length]] > 1 or [[ResolveValue]] returns null
+ * or an r with r.[[Length]] != 1, throw TypeError.
+ */
+ n = JSXML_LENGTH(xml);
+ if (n > 1)
+ goto type_error;
+ if (n == 0) {
+ ok = ResolveValue(cx, xml, &rxml);
+ if (!ok)
+ goto out;
+ if (!rxml || JSXML_LENGTH(rxml) != 1)
+ goto type_error;
+ ok = Append(cx, xml, rxml);
+ if (!ok)
+ goto out;
+ }
+ JS_ASSERT(JSXML_LENGTH(xml) == 1);
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
+ if (!kid)
+ goto out;
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ goto bad;
+ ok = PutProperty(cx, kidobj, id, vp);
+ if (!ok)
+ goto out;
+ }
+ } else {
+ /*
+ * ECMA-357 9.1.1.2.
+ * Erratum: move steps 3 and 4 to before 1 and 2, to avoid wasted
+ * effort in ToString or [[DeepCopy]].
+ */
+ if (js_IdIsIndex(id, &index)) {
+ /* See NOTE in spec: this variation is reserved for future use. */
+ ReportBadXMLName(cx, id);
+ goto bad;
+ }
+
+ nameqn = ToXMLName(cx, id, &funid);
+ if (!nameqn)
+ goto bad;
+ if (funid) {
+ ok = js_SetProperty(cx, obj, funid, vp);
+ goto out;
+ }
+ nameobj = nameqn->object;
+
+ if (JSXML_HAS_VALUE(xml))
+ goto out;
+
+ if (!vxml ||
+ vxml->xml_class == JSXML_CLASS_TEXT ||
+ vxml->xml_class == JSXML_CLASS_ATTRIBUTE) {
+ ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp);
+ if (!ok)
+ goto out;
+ } else {
+ rxml = DeepCopyInLRS(cx, vxml, 0);
+ if (!rxml || !js_GetXMLObject(cx, rxml))
+ goto bad;
+ vxml = rxml;
+ *vp = OBJECT_TO_JSVAL(vxml->object);
+ }
+ roots[VAL_ROOT] = *vp;
+
+ /*
+ * 6.
+ * Erratum: why is this done here, so early? use is way later....
+ */
+ ok = js_GetDefaultXMLNamespace(cx, &nsval);
+ if (!ok)
+ goto out;
+
+ if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) {
+ /* 7(a). */
+ if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj)))
+ goto out;
+
+ /* 7(b-c). */
+ if (vxml && vxml->xml_class == JSXML_CLASS_LIST) {
+ n = vxml->xml_kids.length;
+ if (n == 0) {
+ *vp = STRING_TO_JSVAL(cx->runtime->emptyString);
+ } else {
+ left = KidToString(cx, vxml, 0);
+ if (!left)
+ goto bad;
+
+ space = ATOM_TO_STRING(cx->runtime->atomState.spaceAtom);
+ for (i = 1; i < n; i++) {
+ left = js_ConcatStrings(cx, left, space);
+ if (!left)
+ goto bad;
+ right = KidToString(cx, vxml, i);
+ if (!right)
+ goto bad;
+ left = js_ConcatStrings(cx, left, right);
+ if (!left)
+ goto bad;
+ }
+
+ roots[VAL_ROOT] = *vp = STRING_TO_JSVAL(left);
+ }
+ } else {
+ ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp);
+ if (!ok)
+ goto out;
+ roots[VAL_ROOT] = *vp;
+ }
+
+ /* 7(d-e). */
+ match = NULL;
+ for (i = 0, n = xml->xml_attrs.length; i < n; i++) {
+ attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML);
+ if (!attr)
+ continue;
+ attrqn = attr->name;
+ if (!js_CompareStrings(attrqn->localName, nameqn->localName) &&
+ (!nameqn->uri ||
+ !js_CompareStrings(attrqn->uri, nameqn->uri))) {
+ if (!match) {
+ match = attr;
+ } else {
+ nameobj = js_GetAttributeNameObject(cx, attrqn);
+ if (!nameobj)
+ goto bad;
+
+ id = OBJECT_TO_JSVAL(nameobj);
+ ok = DeleteProperty(cx, obj, id, &junk);
+ if (!ok)
+ goto out;
+ --i;
+ }
+ }
+ }
+
+ /* 7(f). */
+ attr = match;
+ if (!attr) {
+ /* 7(f)(i-ii). */
+ if (!nameqn->uri) {
+ left = right = cx->runtime->emptyString;
+ } else {
+ left = nameqn->uri;
+ right = nameqn->prefix;
+ }
+ nameqn = js_NewXMLQName(cx, left, right, nameqn->localName);
+ if (!nameqn)
+ goto bad;
+
+ /* 7(f)(iii). */
+ attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE);
+ if (!attr)
+ goto bad;
+ attr->parent = xml;
+ attr->name = nameqn;
+
+ /* 7(f)(iv). */
+ ok = XMLARRAY_ADD_MEMBER(cx, &xml->xml_attrs, n, attr);
+ if (!ok)
+ goto out;
+
+ /* 7(f)(v-vi). */
+ ns = GetNamespace(cx, nameqn, NULL);
+ if (!ns)
+ goto bad;
+ ok = AddInScopeNamespace(cx, xml, ns);
+ if (!ok)
+ goto out;
+ }
+
+ /* 7(g). */
+ attr->xml_value = JSVAL_TO_STRING(*vp);
+ goto out;
+ }
+
+ /* 8-9. */
+ if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj)) &&
+ !IS_STAR(nameqn->localName)) {
+ goto out;
+ }
+
+ /* 10-11. */
+ id = JSVAL_VOID;
+ primitiveAssign = !vxml && !IS_STAR(nameqn->localName);
+
+ /* 12. */
+ k = n = xml->xml_kids.length;
+ kid2 = NULL;
+ while (k != 0) {
+ --k;
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, k, JSXML);
+ if (kid && MatchElemName(nameqn, kid)) {
+ if (!JSVAL_IS_VOID(id)) {
+ ok = DeleteByIndex(cx, xml, id, &junk);
+ if (!ok)
+ goto out;
+ }
+ ok = IndexToIdVal(cx, k, &id);
+ if (!ok)
+ goto out;
+ kid2 = kid;
+ }
+ }
+
+ /*
+ * Erratum: ECMA-357 specified child insertion inconsistently:
+ * insertChildBefore and insertChildAfter insert an arbitrary XML
+ * instance, and therefore can create cycles, but appendChild as
+ * specified by the "Overview" of 13.4.4.3 calls [[DeepCopy]] on
+ * its argument. But the "Semantics" in 13.4.4.3 do not include
+ * any [[DeepCopy]] call.
+ *
+ * Fixing this (https://bugzilla.mozilla.org/show_bug.cgi?id=312692)
+ * required adding cycle detection, and allowing duplicate kids to
+ * be created (see comment 6 in the bug). Allowing duplicate kid
+ * references means the loop above will delete all but the lowest
+ * indexed reference, and each [[DeleteByIndex]] nulls the kid's
+ * parent. Thus the need to restore parent here. This is covered
+ * by https://bugzilla.mozilla.org/show_bug.cgi?id=327564.
+ */
+ if (kid2) {
+ JS_ASSERT(kid2->parent == xml || !kid2->parent);
+ if (!kid2->parent)
+ kid2->parent = xml;
+ }
+
+ /* 13. */
+ if (JSVAL_IS_VOID(id)) {
+ /* 13(a). */
+ ok = IndexToIdVal(cx, n, &id);
+ if (!ok)
+ goto out;
+
+ /* 13(b). */
+ if (primitiveAssign) {
+ if (!nameqn->uri) {
+ ns = (JSXMLNamespace *)
+ JS_GetPrivate(cx, JSVAL_TO_OBJECT(nsval));
+ left = ns->uri;
+ right = ns->prefix;
+ } else {
+ left = nameqn->uri;
+ right = nameqn->prefix;
+ }
+ nameqn = js_NewXMLQName(cx, left, right, nameqn->localName);
+ if (!nameqn)
+ goto bad;
+
+ /* 13(b)(iii). */
+ vobj = js_NewXMLObject(cx, JSXML_CLASS_ELEMENT);
+ if (!vobj)
+ goto bad;
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ vxml->parent = xml;
+ vxml->name = nameqn;
+
+ /* 13(b)(iv-vi). */
+ ns = GetNamespace(cx, nameqn, NULL);
+ if (!ns)
+ goto bad;
+ ok = Replace(cx, xml, id, OBJECT_TO_JSVAL(vobj));
+ if (!ok)
+ goto out;
+ ok = AddInScopeNamespace(cx, vxml, ns);
+ if (!ok)
+ goto out;
+ }
+ }
+
+ /* 14. */
+ if (primitiveAssign) {
+ JSXMLArrayCursor cursor;
+
+ js_IdIsIndex(id, &index);
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ cursor.index = index;
+ kid = (JSXML *) XMLArrayCursorItem(&cursor);
+ if (JSXML_HAS_KIDS(kid)) {
+ XMLArrayFinish(cx, &kid->xml_kids);
+ ok = XMLArrayInit(cx, &kid->xml_kids, 1);
+ }
+
+ /* 14(b-c). */
+ /* XXXbe Erratum? redundant w.r.t. 7(b-c) else clause above */
+ if (ok) {
+ ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp);
+ if (ok && !IS_EMPTY(JSVAL_TO_STRING(*vp))) {
+ roots[VAL_ROOT] = *vp;
+ if ((JSXML *) XMLArrayCursorItem(&cursor) == kid)
+ ok = Replace(cx, kid, JSVAL_ZERO, *vp);
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ } else {
+ /* 15(a). */
+ ok = Replace(cx, xml, id, *vp);
+ }
+ }
+
+out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ JS_LeaveLocalRootScope(cx);
+ return ok;
+
+type_error:
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_XMLLIST_PUT,
+ js_ValueToPrintableString(cx, id));
+bad:
+ ok = JS_FALSE;
+ goto out;
+}
+
+/* ECMA-357 9.1.1.10 XML [[ResolveValue]], 9.2.1.10 XMLList [[ResolveValue]]. */
+static JSBool
+ResolveValue(JSContext *cx, JSXML *list, JSXML **result)
+{
+ JSXML *target, *base;
+ JSXMLQName *targetprop;
+ JSObject *targetpropobj;
+ jsval id, tv;
+
+ /* Our caller must be protecting newborn objects. */
+ JS_ASSERT(cx->localRootStack);
+
+ if (list->xml_class != JSXML_CLASS_LIST || list->xml_kids.length != 0) {
+ if (!js_GetXMLObject(cx, list))
+ return JS_FALSE;
+ *result = list;
+ return JS_TRUE;
+ }
+
+ target = list->xml_target;
+ targetprop = list->xml_targetprop;
+ if (!target || !targetprop || IS_STAR(targetprop->localName)) {
+ *result = NULL;
+ return JS_TRUE;
+ }
+
+ targetpropobj = js_GetXMLQNameObject(cx, targetprop);
+ if (!targetpropobj)
+ return JS_FALSE;
+ if (OBJ_GET_CLASS(cx, targetpropobj) == &js_AttributeNameClass) {
+ *result = NULL;
+ return JS_TRUE;
+ }
+
+ if (!ResolveValue(cx, target, &base))
+ return JS_FALSE;
+ if (!base) {
+ *result = NULL;
+ return JS_TRUE;
+ }
+ if (!js_GetXMLObject(cx, base))
+ return JS_FALSE;
+
+ id = OBJECT_TO_JSVAL(targetpropobj);
+ if (!GetProperty(cx, base->object, id, &tv))
+ return JS_FALSE;
+ target = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(tv));
+
+ if (JSXML_LENGTH(target) == 0) {
+ if (base->xml_class == JSXML_CLASS_LIST && JSXML_LENGTH(base) > 1) {
+ *result = NULL;
+ return JS_TRUE;
+ }
+ tv = STRING_TO_JSVAL(cx->runtime->emptyString);
+ if (!PutProperty(cx, base->object, id, &tv))
+ return JS_FALSE;
+ if (!GetProperty(cx, base->object, id, &tv))
+ return JS_FALSE;
+ target = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(tv));
+ }
+
+ *result = target;
+ return JS_TRUE;
+}
+
+/*
+ * HasProperty must be able to return a found JSProperty and the object in
+ * which it was found, if id is of the form function::name. For other ids,
+ * if they index or name an XML child, we return FOUND_XML_PROPERTY in *propp
+ * and null in *objp.
+ *
+ * DROP_PROPERTY helps HasProperty callers drop function properties without
+ * trying to drop the magic FOUND_XML_PROPERTY cookie.
+ */
+#define FOUND_XML_PROPERTY ((JSProperty *) 1)
+#define DROP_PROPERTY(cx,pobj,prop) (((prop) != FOUND_XML_PROPERTY) \
+ ? OBJ_DROP_PROPERTY(cx, pobj, prop) \
+ : (void) 0)
+
+/* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */
+static JSBool
+HasProperty(JSContext *cx, JSObject *obj, jsval id, JSObject **objp,
+ JSProperty **propp)
+{
+ JSXML *xml, *kid;
+ JSXMLArrayCursor cursor;
+ JSObject *kidobj;
+ JSXMLQName *qn;
+ jsid funid;
+ JSXMLArray *array;
+ JSXMLNameMatcher matcher;
+ uint32 i, n;
+
+ *objp = NULL;
+ *propp = NULL;
+
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ n = JSXML_LENGTH(xml);
+ if (js_IdIsIndex(id, &i)) {
+ if (i < n)
+ *propp = FOUND_XML_PROPERTY;
+ return JS_TRUE;
+ }
+
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ if (kid->xml_class == JSXML_CLASS_ELEMENT) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj || !HasProperty(cx, kidobj, id, objp, propp))
+ break;
+ if (*propp)
+ break;
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ if (kid)
+ return *propp != NULL;
+ } else {
+ if (xml->xml_class == JSXML_CLASS_ELEMENT && js_IdIsIndex(id, &i)) {
+ if (i == 0)
+ *propp = FOUND_XML_PROPERTY;
+ return JS_TRUE;
+ }
+
+ qn = ToXMLName(cx, id, &funid);
+ if (!qn)
+ return JS_FALSE;
+ if (funid)
+ return js_LookupProperty(cx, obj, funid, objp, propp);
+
+ if (xml->xml_class != JSXML_CLASS_ELEMENT)
+ return JS_TRUE;
+
+ if (OBJ_GET_CLASS(cx, qn->object) == &js_AttributeNameClass) {
+ array = &xml->xml_attrs;
+ matcher = MatchAttrName;
+ } else {
+ array = &xml->xml_kids;
+ matcher = MatchElemName;
+ }
+ for (i = 0, n = array->length; i < n; i++) {
+ kid = XMLARRAY_MEMBER(array, i, JSXML);
+ if (kid && matcher(qn, kid)) {
+ *propp = FOUND_XML_PROPERTY;
+ return JS_TRUE;
+ }
+ }
+ }
+
+ return JS_TRUE;
+}
+
+static void
+xml_finalize(JSContext *cx, JSObject *obj)
+{
+ JSXML *xml;
+
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ if (!xml)
+ return;
+ if (xml->object == obj)
+ xml->object = NULL;
+ UNMETER(xml_stats.livexmlobj);
+}
+
+static void
+xml_mark_vector(JSContext *cx, JSXML **vec, uint32 len, void *arg)
+{
+ uint32 i;
+ JSXML *elt;
+
+ for (i = 0; i < len; i++) {
+ elt = vec[i];
+ {
+#ifdef GC_MARK_DEBUG
+ char buf[120];
+
+ if (elt->xml_class == JSXML_CLASS_LIST) {
+ strcpy(buf, js_XMLList_str);
+ } else if (JSXML_HAS_NAME(elt)) {
+ JSXMLQName *qn = elt->name;
+
+ JS_snprintf(buf, sizeof buf, "%s::%s",
+ qn->uri ? JS_GetStringBytes(qn->uri) : "*",
+ JS_GetStringBytes(qn->localName));
+ } else {
+ JSString *str = elt->xml_value;
+ size_t srclen = JSSTRING_LENGTH(str);
+ size_t dstlen = sizeof buf;
+
+ if (srclen >= sizeof buf / 6)
+ srclen = sizeof buf / 6 - 1;
+ js_DeflateStringToBuffer(cx, JSSTRING_CHARS(str), srclen,
+ buf, &dstlen);
+ }
+#else
+ const char *buf = NULL;
+#endif
+ JS_MarkGCThing(cx, elt, buf, arg);
+ }
+ }
+}
+
+/*
+ * js_XMLObjectOps.newObjectMap == js_NewObjectMap, so XML objects appear to
+ * be native. Therefore, xml_lookupProperty must return a valid JSProperty
+ * pointer parameter via *propp to signify "property found". Since the only
+ * call to xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from
+ * js_FindXMLProperty (in this file) and js_FindProperty (in jsobj.c, called
+ * from jsinterp.c), the only time we add a JSScopeProperty here is when an
+ * unqualified name or XML name is being accessed.
+ *
+ * This scope property both speeds up subsequent js_Find*Property calls, and
+ * keeps the JSOP_NAME code in js_Interpret happy by giving it an sprop with
+ * (getter, setter) == (GetProperty, PutProperty). We can't use that getter
+ * and setter as js_XMLClass's getProperty and setProperty, because doing so
+ * would break the XML methods, which are function-valued properties of the
+ * XML.prototype object.
+ *
+ * NB: xml_deleteProperty must take care to remove any property added here.
+ */
+static JSBool
+xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+ JSProperty **propp)
+{
+ JSScopeProperty *sprop;
+
+ if (!HasProperty(cx, obj, ID_TO_VALUE(id), objp, propp))
+ return JS_FALSE;
+
+ if (*propp == FOUND_XML_PROPERTY) {
+ sprop = js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty,
+ SPROP_INVALID_SLOT, JSPROP_ENUMERATE,
+ 0, 0);
+ if (!sprop)
+ return JS_FALSE;
+
+ JS_LOCK_OBJ(cx, obj);
+ *objp = obj;
+ *propp = (JSProperty *) sprop;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ JSProperty **propp)
+{
+ if (JSVAL_IS_FUNCTION(cx, value) || getter || setter ||
+ (attrs & JSPROP_ENUMERATE) == 0 ||
+ (attrs & (JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED))) {
+ return js_DefineProperty(cx, obj, id, value, getter, setter, attrs,
+ propp);
+ }
+
+ if (!PutProperty(cx, obj, ID_TO_VALUE(id), &value))
+ return JS_FALSE;
+ if (propp)
+ *propp = NULL;
+ return JS_TRUE;
+}
+
+static JSBool
+xml_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ if (id == JS_DEFAULT_XML_NAMESPACE_ID) {
+ *vp = JSVAL_VOID;
+ return JS_TRUE;
+ }
+
+ return GetProperty(cx, obj, ID_TO_VALUE(id), vp);
+}
+
+static JSBool
+xml_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ return PutProperty(cx, obj, ID_TO_VALUE(id), vp);
+}
+
+static JSBool
+FoundProperty(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ JSBool *foundp)
+{
+ JSObject *pobj;
+
+ if (prop) {
+ *foundp = JS_TRUE;
+ } else {
+ if (!HasProperty(cx, obj, ID_TO_VALUE(id), &pobj, &prop))
+ return JS_FALSE;
+ if (prop)
+ DROP_PROPERTY(cx, pobj, prop);
+ *foundp = (prop != NULL);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp)
+{
+ JSBool found;
+
+ if (!FoundProperty(cx, obj, id, prop, &found))
+ return JS_FALSE;
+ *attrsp = found ? JSPROP_ENUMERATE : 0;
+ return JS_TRUE;
+}
+
+static JSBool
+xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
+ uintN *attrsp)
+{
+ JSBool found;
+
+ if (!FoundProperty(cx, obj, id, prop, &found))
+ return JS_FALSE;
+ if (found) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_SET_XML_ATTRS);
+ }
+ return !found;
+}
+
+static JSBool
+xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
+{
+ /*
+ * If this object has its own (mutable) scope, and if id isn't an index,
+ * then we may have added a property to the scope in xml_lookupProperty
+ * for it to return to mean "found" and to provide a handle for access
+ * operations to call the property's getter or setter. The property also
+ * helps speed up unqualified accesses via the property cache, avoiding
+ * what amount to two HasProperty searches.
+ *
+ * But now it's time to remove any such property, to purge the property
+ * cache and remove the scope entry.
+ */
+ if (OBJ_SCOPE(obj)->object == obj && !JSID_IS_INT(id)) {
+ if (!js_DeleteProperty(cx, obj, id, rval))
+ return JS_FALSE;
+ }
+
+ return DeleteProperty(cx, obj, ID_TO_VALUE(id), rval);
+}
+
+static JSBool
+xml_defaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
+{
+ JSXML *xml;
+
+ if (hint == JSTYPE_OBJECT) {
+ /* Called from for..in code in js_Interpret: return an XMLList. */
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ if (xml->xml_class != JSXML_CLASS_LIST) {
+ obj = ToXMLList(cx, OBJECT_TO_JSVAL(obj));
+ if (!obj)
+ return JS_FALSE;
+ }
+ *vp = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+ }
+
+ return JS_CallFunctionName(cx, obj, js_toString_str, 0, NULL, vp);
+}
+
+static JSBool
+xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+ jsval *statep, jsid *idp)
+{
+ JSXML *xml;
+ uint32 length, index;
+ JSXMLArrayCursor *cursor;
+
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ length = JSXML_LENGTH(xml);
+
+ switch (enum_op) {
+ case JSENUMERATE_INIT:
+ if (length == 0) {
+ cursor = NULL;
+ } else {
+ cursor = (JSXMLArrayCursor *) JS_malloc(cx, sizeof *cursor);
+ if (!cursor)
+ return JS_FALSE;
+ XMLArrayCursorInit(cursor, &xml->xml_kids);
+ }
+ *statep = PRIVATE_TO_JSVAL(cursor);
+ if (idp)
+ *idp = INT_TO_JSID(length);
+ break;
+
+ case JSENUMERATE_NEXT:
+ cursor = JSVAL_TO_PRIVATE(*statep);
+ if (cursor && cursor->array && (index = cursor->index) < length) {
+ *idp = INT_TO_JSID(index);
+ cursor->index = index + 1;
+ break;
+ }
+ /* FALL THROUGH */
+
+ case JSENUMERATE_DESTROY:
+ cursor = JSVAL_TO_PRIVATE(*statep);
+ if (cursor) {
+ XMLArrayCursorFinish(cursor);
+ JS_free(cx, cursor);
+ }
+ *statep = JSVAL_NULL;
+ break;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+xml_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+{
+ return JS_TRUE;
+}
+
+static uint32
+xml_mark(JSContext *cx, JSObject *obj, void *arg)
+{
+ JSXML *xml;
+
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ JS_MarkGCThing(cx, xml, js_private_str, arg);
+ return js_Mark(cx, obj, arg);
+}
+
+static void
+xml_clear(JSContext *cx, JSObject *obj)
+{
+}
+
+static JSBool
+HasSimpleContent(JSXML *xml)
+{
+ JSXML *kid;
+ JSBool simple;
+ uint32 i, n;
+
+again:
+ switch (xml->xml_class) {
+ case JSXML_CLASS_COMMENT:
+ case JSXML_CLASS_PROCESSING_INSTRUCTION:
+ return JS_FALSE;
+ case JSXML_CLASS_LIST:
+ if (xml->xml_kids.length == 0)
+ return JS_TRUE;
+ if (xml->xml_kids.length == 1) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
+ if (kid) {
+ xml = kid;
+ goto again;
+ }
+ }
+ /* FALL THROUGH */
+ default:
+ simple = JS_TRUE;
+ for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) {
+ simple = JS_FALSE;
+ break;
+ }
+ }
+ return simple;
+ }
+}
+
+/*
+ * 11.2.2.1 Step 3(d) onward.
+ */
+static JSObject *
+xml_getMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ JSXML *xml;
+ JSTempValueRooter tvr;
+ jsval roots[2];
+ enum {
+ FUN_ROOT = 0,
+ OBJ_ROOT = 1
+ };
+
+ JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL));
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ memset(roots, 0, sizeof(roots));
+ JS_PUSH_TEMP_ROOT(cx, sizeof roots / sizeof *roots, roots, &tvr);
+
+ /* From this point the control must flow through out: or bad: */
+ retry:
+ if (!GetFunction(cx, obj, xml, id, &roots[FUN_ROOT]))
+ goto bad;
+ if (JSVAL_IS_VOID(roots[FUN_ROOT]) && OBJECT_IS_XML(cx, obj)) {
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ if (xml->xml_kids.length == 1) {
+ xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
+ if (xml) {
+ obj = js_GetXMLObject(cx, xml);
+ if (!obj)
+ goto bad;
+ roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj);
+ goto retry;
+ }
+ }
+ } else if (HasSimpleContent(xml)) {
+ JSString *str;
+
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ goto bad;
+ if (!js_ValueToObject(cx, STRING_TO_JSVAL(str), &obj))
+ goto bad;
+ roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj);
+ if (!js_GetProperty(cx, obj, id, &roots[FUN_ROOT]))
+ goto bad;
+ }
+ }
+ out:
+ *vp = roots[FUN_ROOT];
+ if (obj) {
+ /*
+ * If we just POP tvr, then it is possible that nothing roots obj, see
+ * bug 353165. To allow our callers to assume at least weakly rooting
+ * of the result, we root obj via newborn array. Similarly we root the
+ * value of roots[FUNCTION] since getMethod callers have a bad habit
+ * of passing a pointer to unrooted local value as vp.
+ */
+ cx->newborn[GCX_OBJECT] = (JSGCThing *)obj;
+ cx->lastInternalResult = roots[FUN_ROOT];
+ }
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return obj;
+ bad:
+ obj = NULL;
+ goto out;
+}
+
+static JSBool
+xml_setMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+ return js_SetProperty(cx, obj, id, vp);
+}
+
+static JSBool
+xml_enumerateValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+ jsval *statep, jsid *idp, jsval *vp)
+{
+ JSXML *xml, *kid;
+ uint32 length, index;
+ JSXMLArrayCursor *cursor;
+ JSObject *kidobj;
+
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ length = JSXML_LENGTH(xml);
+ JS_ASSERT(INT_FITS_IN_JSVAL(length));
+
+ switch (enum_op) {
+ case JSENUMERATE_INIT:
+ if (length == 0) {
+ cursor = NULL;
+ } else {
+ cursor = (JSXMLArrayCursor *) JS_malloc(cx, sizeof *cursor);
+ if (!cursor)
+ return JS_FALSE;
+ XMLArrayCursorInit(cursor, &xml->xml_kids);
+ }
+ *statep = PRIVATE_TO_JSVAL(cursor);
+ if (idp)
+ *idp = INT_TO_JSID(length);
+ if (vp)
+ *vp = JSVAL_VOID;
+ break;
+
+ case JSENUMERATE_NEXT:
+ cursor = JSVAL_TO_PRIVATE(*statep);
+ if (cursor && cursor->array && (index = cursor->index) < length) {
+ while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) {
+ if (++index == length)
+ goto destroy;
+ }
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ return JS_FALSE;
+ JS_ASSERT(INT_FITS_IN_JSVAL(index));
+ *idp = INT_TO_JSID(index);
+ *vp = OBJECT_TO_JSVAL(kidobj);
+ cursor->index = index + 1;
+ break;
+ }
+ /* FALL THROUGH */
+
+ case JSENUMERATE_DESTROY:
+ cursor = JSVAL_TO_PRIVATE(*statep);
+ if (cursor) {
+ destroy:
+ XMLArrayCursorFinish(cursor);
+ JS_free(cx, cursor);
+ }
+ *statep = JSVAL_NULL;
+ break;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+xml_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+{
+ JSXML *xml, *vxml;
+ JSObject *vobj;
+ JSBool ok;
+ JSString *str, *vstr;
+ jsdouble d, d2;
+
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ vxml = NULL;
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ vobj = JSVAL_TO_OBJECT(v);
+ if (OBJECT_IS_XML(cx, vobj))
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ }
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ ok = Equals(cx, xml, v, bp);
+ } else if (vxml) {
+ if (vxml->xml_class == JSXML_CLASS_LIST) {
+ ok = Equals(cx, vxml, OBJECT_TO_JSVAL(obj), bp);
+ } else {
+ if (((xml->xml_class == JSXML_CLASS_TEXT ||
+ xml->xml_class == JSXML_CLASS_ATTRIBUTE) &&
+ HasSimpleContent(vxml)) ||
+ ((vxml->xml_class == JSXML_CLASS_TEXT ||
+ vxml->xml_class == JSXML_CLASS_ATTRIBUTE) &&
+ HasSimpleContent(xml))) {
+ ok = JS_EnterLocalRootScope(cx);
+ if (ok) {
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ vstr = js_ValueToString(cx, v);
+ ok = str && vstr;
+ if (ok)
+ *bp = !js_CompareStrings(str, vstr);
+ JS_LeaveLocalRootScope(cx);
+ }
+ } else {
+ ok = XMLEquals(cx, xml, vxml, bp);
+ }
+ }
+ } else {
+ ok = JS_EnterLocalRootScope(cx);
+ if (ok) {
+ if (HasSimpleContent(xml)) {
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ vstr = js_ValueToString(cx, v);
+ ok = str && vstr;
+ if (ok)
+ *bp = !js_CompareStrings(str, vstr);
+ } else if (JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v)) {
+ str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str) {
+ ok = JS_FALSE;
+ } else if (JSVAL_IS_STRING(v)) {
+ *bp = !js_CompareStrings(str, JSVAL_TO_STRING(v));
+ } else {
+ ok = js_ValueToNumber(cx, STRING_TO_JSVAL(str), &d);
+ if (ok) {
+ d2 = JSVAL_IS_INT(v) ? JSVAL_TO_INT(v)
+ : *JSVAL_TO_DOUBLE(v);
+ *bp = JSDOUBLE_COMPARE(d, ==, d2, JS_FALSE);
+ }
+ }
+ } else {
+ *bp = JS_FALSE;
+ }
+ JS_LeaveLocalRootScope(cx);
+ }
+ }
+ return ok;
+}
+
+static JSBool
+xml_concatenate(JSContext *cx, JSObject *obj, jsval v, jsval *vp)
+{
+ JSBool ok;
+ JSObject *listobj, *robj;
+ JSXML *list, *lxml, *rxml;
+
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ return JS_FALSE;
+
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ lxml = (JSXML *) JS_GetPrivate(cx, obj);
+ ok = Append(cx, list, lxml);
+ if (!ok)
+ goto out;
+
+ if (VALUE_IS_XML(cx, v)) {
+ rxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ } else {
+ robj = ToXML(cx, v);
+ if (!robj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ rxml = (JSXML *) JS_GetPrivate(cx, robj);
+ }
+ ok = Append(cx, list, rxml);
+ if (!ok)
+ goto out;
+
+ *vp = OBJECT_TO_JSVAL(listobj);
+out:
+ JS_LeaveLocalRootScope(cx);
+ return ok;
+}
+
+/* Use js_NewObjectMap so XML objects satisfy OBJ_IS_NATIVE tests. */
+JS_FRIEND_DATA(JSXMLObjectOps) js_XMLObjectOps = {
+ { js_NewObjectMap, js_DestroyObjectMap,
+ xml_lookupProperty, xml_defineProperty,
+ xml_getProperty, xml_setProperty,
+ xml_getAttributes, xml_setAttributes,
+ xml_deleteProperty, xml_defaultValue,
+ xml_enumerate, js_CheckAccess,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, xml_hasInstance,
+ js_SetProtoOrParent, js_SetProtoOrParent,
+ xml_mark, xml_clear,
+ NULL, NULL },
+ xml_getMethod, xml_setMethod,
+ xml_enumerateValues, xml_equality,
+ xml_concatenate
+};
+
+static JSObjectOps *
+xml_getObjectOps(JSContext *cx, JSClass *clasp)
+{
+ return &js_XMLObjectOps.base;
+}
+
+JS_FRIEND_DATA(JSClass) js_XMLClass = {
+ js_XML_str, JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xml_finalize,
+ xml_getObjectOps, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+static JSObject *
+CallConstructorFunction(JSContext *cx, JSObject *obj, JSClass *clasp,
+ uintN argc, jsval *argv)
+{
+ JSObject *tmp;
+ jsval rval;
+
+ while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
+ obj = tmp;
+ if (!JS_CallFunctionName(cx, obj, clasp->name, argc, argv, &rval))
+ return NULL;
+ JS_ASSERT(!JSVAL_IS_PRIMITIVE(rval));
+ return JSVAL_TO_OBJECT(rval);
+}
+
+#define XML_METHOD_PROLOG \
+ JS_BEGIN_MACRO \
+ xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, argv); \
+ if (!xml) \
+ return JS_FALSE; \
+ JS_END_MACRO
+
+static JSBool
+xml_addNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ JSObject *nsobj;
+ JSXMLNamespace *ns;
+
+ XML_METHOD_PROLOG;
+ if (xml->xml_class != JSXML_CLASS_ELEMENT)
+ return JS_TRUE;
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+
+ nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, argv);
+ if (!nsobj)
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(nsobj);
+
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj);
+ if (!AddInScopeNamespace(cx, xml, ns))
+ return JS_FALSE;
+ ns->declared = JS_TRUE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+static JSBool
+xml_appendChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *vxml;
+ jsval name, v;
+ JSObject *vobj;
+
+ XML_METHOD_PROLOG;
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+
+ if (!js_GetAnyName(cx, &name))
+ return JS_FALSE;
+
+ if (!GetProperty(cx, obj, name, &v))
+ return JS_FALSE;
+
+ JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
+ vobj = JSVAL_TO_OBJECT(v);
+ JS_ASSERT(OBJECT_IS_XML(cx, vobj));
+ vxml = (JSXML *) JS_GetPrivate(cx, vobj);
+ JS_ASSERT(vxml->xml_class == JSXML_CLASS_LIST);
+
+ if (!IndexToIdVal(cx, vxml->xml_kids.length, &name))
+ return JS_FALSE;
+ if (!PutProperty(cx, JSVAL_TO_OBJECT(v), name, &argv[0]))
+ return JS_FALSE;
+
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_attribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXMLQName *qn;
+
+ qn = ToAttributeName(cx, argv[0]);
+ if (!qn)
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(qn->object); /* local root */
+ return GetProperty(cx, obj, argv[0], rval);
+}
+
+/* XML and XMLList */
+static JSBool
+xml_attributes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval name;
+ JSXMLQName *qn;
+ JSTempValueRooter tvr;
+ JSBool ok;
+
+ name = ATOM_KEY(cx->runtime->atomState.starAtom);
+ qn = ToAttributeName(cx, name);
+ if (!qn)
+ return JS_FALSE;
+ name = OBJECT_TO_JSVAL(qn->object);
+ JS_PUSH_SINGLE_TEMP_ROOT(cx, name, &tvr);
+ ok = GetProperty(cx, obj, name, rval);
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return ok;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name,
+ jsval *rval)
+{
+ uint32 index;
+ JSXML *kid;
+ JSObject *kidobj;
+
+ /* ECMA-357 13.4.4.6 */
+ JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST);
+
+ if (js_IdIsIndex(name, &index)) {
+ if (index >= JSXML_LENGTH(xml)) {
+ *rval = JSVAL_VOID;
+ } else {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML);
+ if (!kid) {
+ *rval = JSVAL_VOID;
+ } else {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(kidobj);
+ }
+ }
+ return JS_TRUE;
+ }
+
+ return GetProperty(cx, obj, name, rval);
+}
+
+static JSBool
+xml_child(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml, *list, *kid, *vxml;
+ JSXMLArrayCursor cursor;
+ jsval name, v;
+ JSObject *listobj, *kidobj;
+
+ XML_METHOD_PROLOG;
+ name = argv[0];
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* ECMA-357 13.5.4.4 */
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ return JS_FALSE;
+
+ *rval = OBJECT_TO_JSVAL(listobj);
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ list->xml_target = xml;
+
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ break;
+ if (!xml_child_helper(cx, kidobj, kid, name, &v))
+ break;
+ if (JSVAL_IS_VOID(v)) {
+ /* The property didn't exist in this kid. */
+ continue;
+ }
+
+ JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
+ vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ if ((!JSXML_HAS_KIDS(vxml) || vxml->xml_kids.length != 0) &&
+ !Append(cx, list, vxml)) {
+ break;
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ return !kid;
+ }
+
+ return xml_child_helper(cx, obj, xml, name, rval);
+}
+
+static JSBool
+xml_childIndex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *parent;
+ uint32 i, n;
+
+ XML_METHOD_PROLOG;
+ parent = xml->parent;
+ if (!parent || xml->xml_class == JSXML_CLASS_ATTRIBUTE) {
+ *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ return JS_TRUE;
+ }
+ for (i = 0, n = JSXML_LENGTH(parent); i < n; i++) {
+ if (XMLARRAY_MEMBER(&parent->xml_kids, i, JSXML) == xml)
+ break;
+ }
+ JS_ASSERT(i < n);
+ return js_NewNumberValue(cx, i, rval);
+}
+
+/* XML and XMLList */
+static JSBool
+xml_children(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval name;
+
+ name = ATOM_KEY(cx->runtime->atomState.starAtom);
+ return GetProperty(cx, obj, name, rval);
+}
+
+/* XML and XMLList */
+static JSBool
+xml_comments(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *list, *kid, *vxml;
+ JSObject *listobj, *kidobj;
+ JSBool ok;
+ uint32 i, n;
+ jsval v;
+
+ XML_METHOD_PROLOG;
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ return JS_FALSE;
+
+ *rval = OBJECT_TO_JSVAL(listobj);
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ list->xml_target = xml;
+
+ ok = JS_TRUE;
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* 13.5.4.6 Step 2. */
+ for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) {
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ break;
+ kidobj = js_GetXMLObject(cx, kid);
+ ok = kidobj
+ ? xml_comments(cx, kidobj, argc, argv, &v)
+ : JS_FALSE;
+ JS_LeaveLocalRootScope(cx);
+ if (!ok)
+ break;
+ vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ if (JSXML_LENGTH(vxml) != 0) {
+ ok = Append(cx, list, vxml);
+ if (!ok)
+ break;
+ }
+ }
+ }
+ } else {
+ /* 13.4.4.9 Step 2. */
+ for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_COMMENT) {
+ ok = Append(cx, list, kid);
+ if (!ok)
+ break;
+ }
+ }
+ }
+
+ return ok;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_contains(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *kid;
+ jsval value;
+ JSBool eq;
+ JSXMLArrayCursor cursor;
+ JSObject *kidobj;
+
+ XML_METHOD_PROLOG;
+ value = argv[0];
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ eq = JS_FALSE;
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj || !xml_equality(cx, kidobj, value, &eq))
+ break;
+ if (eq)
+ break;
+ }
+ XMLArrayCursorFinish(&cursor);
+ if (kid)
+ return JS_FALSE;
+ } else {
+ if (!xml_equality(cx, obj, value, &eq))
+ return JS_FALSE;
+ }
+ *rval = BOOLEAN_TO_JSVAL(eq);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_copy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml, *copy;
+
+ XML_METHOD_PROLOG;
+ copy = DeepCopy(cx, xml, NULL, 0);
+ if (!copy)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(copy->object);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_descendants(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *list;
+ jsval name;
+
+ XML_METHOD_PROLOG;
+ name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0];
+ list = Descendants(cx, xml, name);
+ if (!list)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(list->object);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_elements(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *list, *kid, *vxml;
+ jsval name, v;
+ JSXMLQName *nameqn;
+ jsid funid;
+ JSObject *listobj, *kidobj;
+ JSBool ok;
+ JSXMLArrayCursor cursor;
+ uint32 i, n;
+
+ XML_METHOD_PROLOG;
+ name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0];
+ nameqn = ToXMLName(cx, name, &funid);
+ if (!nameqn)
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(nameqn->object);
+
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(listobj);
+ if (funid)
+ return JS_TRUE;
+
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ list->xml_target = xml;
+ list->xml_targetprop = nameqn;
+ ok = JS_TRUE;
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* 13.5.4.6 */
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ if (kid->xml_class == JSXML_CLASS_ELEMENT) {
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ break;
+ kidobj = js_GetXMLObject(cx, kid);
+ ok = kidobj
+ ? xml_elements(cx, kidobj, argc, argv, &v)
+ : JS_FALSE;
+ JS_LeaveLocalRootScope(cx);
+ if (!ok)
+ break;
+ vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ if (JSXML_LENGTH(vxml) != 0) {
+ ok = Append(cx, list, vxml);
+ if (!ok)
+ break;
+ }
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ } else {
+ for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT &&
+ MatchElemName(nameqn, kid)) {
+ ok = Append(cx, list, kid);
+ if (!ok)
+ break;
+ }
+ }
+ }
+
+ return ok;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_hasOwnProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval name;
+ JSObject *pobj;
+ JSProperty *prop;
+
+ if (!JS_InstanceOf(cx, obj, &js_XMLClass, argv))
+ return JS_FALSE;
+
+ name = argv[0];
+ if (!HasProperty(cx, obj, name, &pobj, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ return js_HasOwnPropertyHelper(cx, obj, js_LookupProperty, argc, argv,
+ rval);
+ }
+ DROP_PROPERTY(cx, pobj, prop);
+ *rval = JSVAL_TRUE;
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_hasComplexContent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *kid;
+ JSObject *kidobj;
+ uint32 i, n;
+
+ XML_METHOD_PROLOG;
+again:
+ switch (xml->xml_class) {
+ case JSXML_CLASS_ATTRIBUTE:
+ case JSXML_CLASS_COMMENT:
+ case JSXML_CLASS_PROCESSING_INSTRUCTION:
+ case JSXML_CLASS_TEXT:
+ *rval = JSVAL_FALSE;
+ break;
+ case JSXML_CLASS_LIST:
+ if (xml->xml_kids.length == 0) {
+ *rval = JSVAL_TRUE;
+ } else if (xml->xml_kids.length == 1) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
+ if (kid) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ return JS_FALSE;
+ obj = kidobj;
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ goto again;
+ }
+ }
+ /* FALL THROUGH */
+ default:
+ *rval = JSVAL_FALSE;
+ for (i = 0, n = xml->xml_kids.length; i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) {
+ *rval = JSVAL_TRUE;
+ break;
+ }
+ }
+ break;
+ }
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_hasSimpleContent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+
+ XML_METHOD_PROLOG;
+ *rval = BOOLEAN_TO_JSVAL(HasSimpleContent(xml));
+ return JS_TRUE;
+}
+
+typedef struct JSTempRootedNSArray {
+ JSTempValueRooter tvr;
+ JSXMLArray array;
+ jsval value; /* extra root for temporaries */
+} JSTempRootedNSArray;
+
+JS_STATIC_DLL_CALLBACK(void)
+mark_temp_ns_array(JSContext *cx, JSTempValueRooter *tvr)
+{
+ JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr;
+
+ namespace_mark_vector(cx,
+ (JSXMLNamespace **)tmp->array.vector,
+ tmp->array.length, NULL);
+ XMLArrayCursorMark(cx, tmp->array.cursors);
+ if (JSVAL_IS_GCTHING(tmp->value))
+ GC_MARK(cx, JSVAL_TO_GCTHING(tmp->value), "temp_ns_array_value", NULL);
+}
+
+static void
+InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp)
+{
+ XMLArrayInit(cx, &tmp->array, 0);
+ tmp->value = JSVAL_NULL;
+ JS_PUSH_TEMP_ROOT_MARKER(cx, mark_temp_ns_array, &tmp->tvr);
+}
+
+static void
+FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp)
+{
+ JS_ASSERT(tmp->tvr.u.marker == mark_temp_ns_array);
+ JS_POP_TEMP_ROOT(cx, &tmp->tvr);
+ XMLArrayFinish(cx, &tmp->array);
+}
+
+/*
+ * Populate a new JS array with elements of JSTempRootedNSArray.array and
+ * place the result into rval. rval must point to a rooted location.
+ */
+static JSBool
+TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval)
+{
+ JSObject *arrayobj;
+ uint32 i, n;
+ JSXMLNamespace *ns;
+ JSObject *nsobj;
+
+ arrayobj = js_NewArrayObject(cx, 0, NULL);
+ if (!arrayobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(arrayobj);
+ for (i = 0, n = tmp->array.length; i < n; i++) {
+ ns = XMLARRAY_MEMBER(&tmp->array, i, JSXMLNamespace);
+ if (!ns)
+ continue;
+ nsobj = js_GetXMLNamespaceObject(cx, ns);
+ if (!nsobj)
+ return JS_FALSE;
+ tmp->value = OBJECT_TO_JSVAL(nsobj);
+ if (!OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(i), &tmp->value))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray)
+{
+ uint32 length, i, j, n;
+ JSXMLNamespace *ns, *ns2;
+
+ length = nsarray->length;
+ do {
+ if (xml->xml_class != JSXML_CLASS_ELEMENT)
+ continue;
+ for (i = 0, n = xml->xml_namespaces.length; i < n; i++) {
+ ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace);
+ if (!ns)
+ continue;
+
+ for (j = 0; j < length; j++) {
+ ns2 = XMLARRAY_MEMBER(nsarray, j, JSXMLNamespace);
+ if (ns2 &&
+ ((ns2->prefix && ns->prefix)
+ ? !js_CompareStrings(ns2->prefix, ns->prefix)
+ : !js_CompareStrings(ns2->uri, ns->uri))) {
+ break;
+ }
+ }
+
+ if (j == length) {
+ if (!XMLARRAY_APPEND(cx, nsarray, ns))
+ return JS_FALSE;
+ ++length;
+ }
+ }
+ } while ((xml = xml->parent) != NULL);
+ JS_ASSERT(length == nsarray->length);
+
+ return JS_TRUE;
+}
+
+static JSBool
+xml_inScopeNamespaces(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ JSTempRootedNSArray namespaces;
+ JSBool ok;
+
+ XML_METHOD_PROLOG;
+
+ InitTempNSArray(cx, &namespaces);
+ ok = FindInScopeNamespaces(cx, xml, &namespaces.array) &&
+ TempNSArrayToJSArray(cx, &namespaces, rval);
+ FinishTempNSArray(cx, &namespaces);
+ return ok;
+}
+
+static JSBool
+xml_insertChildAfter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *kid;
+ jsval arg;
+ uint32 i;
+
+ XML_METHOD_PROLOG;
+ if (!JSXML_HAS_KIDS(xml))
+ return JS_TRUE;
+
+ arg = argv[0];
+ if (JSVAL_IS_NULL(arg)) {
+ kid = NULL;
+ i = 0;
+ } else {
+ if (!VALUE_IS_XML(cx, arg))
+ return JS_TRUE;
+ kid = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(arg));
+ i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL);
+ if (i == XML_NOT_FOUND)
+ return JS_TRUE;
+ ++i;
+ }
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+ if (!Insert(cx, xml, i, argv[1]))
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+static JSBool
+xml_insertChildBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *kid;
+ jsval arg;
+ uint32 i;
+
+ XML_METHOD_PROLOG;
+ if (!JSXML_HAS_KIDS(xml))
+ return JS_TRUE;
+
+ arg = argv[0];
+ if (JSVAL_IS_NULL(arg)) {
+ kid = NULL;
+ i = xml->xml_kids.length;
+ } else {
+ if (!VALUE_IS_XML(cx, arg))
+ return JS_TRUE;
+ kid = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(arg));
+ i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL);
+ if (i == XML_NOT_FOUND)
+ return JS_TRUE;
+ }
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+ if (!Insert(cx, xml, i, argv[1]))
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_length(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml;
+
+ XML_METHOD_PROLOG;
+ if (xml->xml_class != JSXML_CLASS_LIST) {
+ *rval = JSVAL_ONE;
+ } else {
+ if (!js_NewNumberValue(cx, xml->xml_kids.length, rval))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+xml_localName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+
+ XML_METHOD_PROLOG;
+ *rval = xml->name ? STRING_TO_JSVAL(xml->name->localName) : JSVAL_NULL;
+ return JS_TRUE;
+}
+
+static JSBool
+xml_name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml;
+ JSObject *nameobj;
+
+ XML_METHOD_PROLOG;
+ if (!xml->name) {
+ *rval = JSVAL_NULL;
+ } else {
+ nameobj = js_GetXMLQNameObject(cx, xml->name);
+ if (!nameobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(nameobj);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+xml_namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ JSString *prefix;
+ JSTempRootedNSArray inScopeNSes;
+ JSBool ok;
+ jsuint i, length;
+ JSXMLNamespace *ns;
+ JSObject *nsobj;
+
+ XML_METHOD_PROLOG;
+ if (argc == 0 &&
+ (xml->xml_class == JSXML_CLASS_TEXT ||
+ xml->xml_class == JSXML_CLASS_COMMENT ||
+ xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION)) {
+ *rval = JSVAL_NULL;
+ return JS_TRUE;
+ }
+
+ if (argc == 0) {
+ prefix = NULL;
+ } else {
+ prefix = js_ValueToString(cx, argv[0]);
+ if (!prefix)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(prefix); /* local root */
+ }
+
+ /* After this point the control must flow through label out. */
+ InitTempNSArray(cx, &inScopeNSes);
+ ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array);
+ if (!ok)
+ goto out;
+
+ if (!prefix) {
+ ns = GetNamespace(cx, xml->name, &inScopeNSes.array);
+ if (!ns) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ } else {
+ ns = NULL;
+ for (i = 0, length = inScopeNSes.array.length; i < length; i++) {
+ ns = XMLARRAY_MEMBER(&inScopeNSes.array, i, JSXMLNamespace);
+ if (ns && ns->prefix && !js_CompareStrings(ns->prefix, prefix))
+ break;
+ ns = NULL;
+ }
+ }
+
+ if (!ns) {
+ *rval = JSVAL_VOID;
+ } else {
+ nsobj = js_GetXMLNamespaceObject(cx, ns);
+ if (!nsobj) {
+ ok = JS_FALSE;
+ goto out;
+ }
+ *rval = OBJECT_TO_JSVAL(nsobj);
+ }
+
+ out:
+ FinishTempNSArray(cx, &inScopeNSes);
+ return JS_TRUE;
+}
+
+static JSBool
+xml_namespaceDeclarations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *yml;
+ JSBool ok;
+ JSTempRootedNSArray ancestors, declared;
+ uint32 i, n;
+ JSXMLNamespace *ns;
+
+ XML_METHOD_PROLOG;
+ if (JSXML_HAS_VALUE(xml) || xml->xml_class == JSXML_CLASS_LIST)
+ return JS_TRUE;
+
+ /* From here, control flow must goto out to finish these arrays. */
+ ok = JS_TRUE;
+ InitTempNSArray(cx, &ancestors);
+ InitTempNSArray(cx, &declared);
+ yml = xml;
+
+ while ((yml = yml->parent) != NULL) {
+ JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT);
+ for (i = 0, n = yml->xml_namespaces.length; i < n; i++) {
+ ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSXMLNamespace);
+ if (ns &&
+ !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) {
+ ok = XMLARRAY_APPEND(cx, &ancestors.array, ns);
+ if (!ok)
+ goto out;
+ }
+ }
+ }
+
+ for (i = 0, n = xml->xml_namespaces.length; i < n; i++) {
+ ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSXMLNamespace);
+ if (!ns)
+ continue;
+ if (!ns->declared)
+ continue;
+ if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) {
+ ok = XMLARRAY_APPEND(cx, &declared.array, ns);
+ if (!ok)
+ goto out;
+ }
+ }
+
+ ok = TempNSArrayToJSArray(cx, &declared, rval);
+
+out:
+ /* Finishing must be in reverse order of initialization to follow LIFO. */
+ FinishTempNSArray(cx, &declared);
+ FinishTempNSArray(cx, &ancestors);
+ return ok;
+}
+
+static const char js_attribute_str[] = "attribute";
+static const char js_text_str[] = "text";
+
+/* Exported to jsgc.c #ifdef GC_MARK_DEBUG. */
+const char *js_xml_class_str[] = {
+ "list",
+ "element",
+ js_attribute_str,
+ "processing-instruction",
+ js_text_str,
+ "comment"
+};
+
+static JSBool
+xml_nodeKind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ JSString *str;
+
+ XML_METHOD_PROLOG;
+ str = JS_InternString(cx, js_xml_class_str[xml->xml_class]);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
+NormalizingDelete(JSContext *cx, JSObject *obj, JSXML *xml, jsval id)
+{
+ jsval junk;
+
+ if (xml->xml_class == JSXML_CLASS_LIST)
+ return DeleteProperty(cx, obj, id, &junk);
+ return DeleteByIndex(cx, xml, id, &junk);
+}
+
+/*
+ * Erratum? the testcase js/tests/e4x/XML/13.4.4.26.js wants all-whitespace
+ * text between tags to be removed by normalize.
+ */
+static JSBool
+IsXMLSpace(JSString *str)
+{
+ const jschar *cp, *end;
+
+ cp = JSSTRING_CHARS(str);
+ end = cp + JSSTRING_LENGTH(str);
+ while (cp < end) {
+ if (!JS_ISXMLSPACE(*cp))
+ return JS_FALSE;
+ ++cp;
+ }
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_normalize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *kid, *kid2;
+ uint32 i, n;
+ JSObject *kidobj;
+ JSString *str;
+ jsval junk;
+
+ XML_METHOD_PROLOG;
+ *rval = OBJECT_TO_JSVAL(obj);
+ if (!JSXML_HAS_KIDS(xml))
+ return JS_TRUE;
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+
+ for (i = 0, n = xml->xml_kids.length; i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (!kid)
+ continue;
+ if (kid->xml_class == JSXML_CLASS_ELEMENT) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj || !xml_normalize(cx, kidobj, argc, argv, &junk))
+ return JS_FALSE;
+ } else if (kid->xml_class == JSXML_CLASS_TEXT) {
+ while (i + 1 < n &&
+ (kid2 = XMLARRAY_MEMBER(&xml->xml_kids, i + 1, JSXML)) &&
+ kid2->xml_class == JSXML_CLASS_TEXT) {
+ str = js_ConcatStrings(cx, kid->xml_value, kid2->xml_value);
+ if (!str)
+ return JS_FALSE;
+ if (!NormalizingDelete(cx, obj, xml, INT_TO_JSVAL(i + 1)))
+ return JS_FALSE;
+ n = xml->xml_kids.length;
+ kid->xml_value = str;
+ }
+ if (IS_EMPTY(kid->xml_value) || IsXMLSpace(kid->xml_value)) {
+ if (!NormalizingDelete(cx, obj, xml, INT_TO_JSVAL(i)))
+ return JS_FALSE;
+ n = xml->xml_kids.length;
+ --i;
+ }
+ }
+ }
+
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_parent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml, *parent, *kid;
+ uint32 i, n;
+ JSObject *parentobj;
+
+ XML_METHOD_PROLOG;
+ parent = xml->parent;
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ *rval = JSVAL_VOID;
+ n = xml->xml_kids.length;
+ if (n == 0)
+ return JS_TRUE;
+
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
+ if (!kid)
+ return JS_TRUE;
+ parent = kid->parent;
+ for (i = 1; i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->parent != parent)
+ return JS_TRUE;
+ }
+ }
+
+ if (!parent) {
+ *rval = JSVAL_NULL;
+ return JS_TRUE;
+ }
+
+ parentobj = js_GetXMLObject(cx, parent);
+ if (!parentobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(parentobj);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_processingInstructions(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ JSXML *xml, *list, *kid, *vxml;
+ jsval name, v;
+ JSXMLQName *nameqn;
+ jsid funid;
+ JSObject *listobj, *kidobj;
+ JSBool ok;
+ JSXMLArrayCursor cursor;
+ uint32 i, n;
+
+ XML_METHOD_PROLOG;
+ name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0];
+ nameqn = ToXMLName(cx, name, &funid);
+ if (!nameqn)
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(nameqn->object);
+
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(listobj);
+ if (funid)
+ return JS_TRUE;
+
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ list->xml_target = xml;
+ list->xml_targetprop = nameqn;
+ ok = JS_TRUE;
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* 13.5.4.17 Step 4 (misnumbered 9 -- Erratum?). */
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ if (kid->xml_class == JSXML_CLASS_ELEMENT) {
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ break;
+ kidobj = js_GetXMLObject(cx, kid);
+ ok = kidobj
+ ? xml_processingInstructions(cx, kidobj, argc, argv, &v)
+ : JS_FALSE;
+ JS_LeaveLocalRootScope(cx);
+ if (!ok)
+ break;
+ vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ if (JSXML_LENGTH(vxml) != 0) {
+ ok = Append(cx, list, vxml);
+ if (!ok)
+ break;
+ }
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ } else {
+ /* 13.4.4.28 Step 4. */
+ for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION &&
+ (IS_STAR(nameqn->localName) ||
+ !js_CompareStrings(nameqn->localName, kid->name->localName))) {
+ ok = Append(cx, list, kid);
+ if (!ok)
+ break;
+ }
+ }
+ }
+
+ return ok;
+}
+
+static JSBool
+xml_prependChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+
+ XML_METHOD_PROLOG;
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(obj);
+ return Insert(cx, xml, 0, argv[0]);
+}
+
+/* XML and XMLList */
+static JSBool
+xml_propertyIsEnumerable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ jsval name;
+ uint32 index;
+
+ XML_METHOD_PROLOG;
+ name = argv[0];
+ *rval = JSVAL_FALSE;
+ if (js_IdIsIndex(name, &index)) {
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ /* 13.5.4.18. */
+ *rval = BOOLEAN_TO_JSVAL(index < xml->xml_kids.length);
+ } else {
+ /* 13.4.4.30. */
+ *rval = BOOLEAN_TO_JSVAL(index == 0);
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+namespace_full_match(const void *a, const void *b)
+{
+ const JSXMLNamespace *nsa = (const JSXMLNamespace *) a;
+ const JSXMLNamespace *nsb = (const JSXMLNamespace *) b;
+
+ if (nsa->prefix && nsb->prefix &&
+ js_CompareStrings(nsa->prefix, nsb->prefix)) {
+ return JS_FALSE;
+ }
+ return !js_CompareStrings(nsa->uri, nsb->uri);
+}
+
+static JSBool
+xml_removeNamespace_helper(JSContext *cx, JSXML *xml, JSXMLNamespace *ns)
+{
+ JSXMLNamespace *thisns, *attrns;
+ uint32 i, n;
+ JSXML *attr, *kid;
+
+ thisns = GetNamespace(cx, xml->name, &xml->xml_namespaces);
+ JS_ASSERT(thisns);
+ if (thisns == ns)
+ return JS_TRUE;
+
+ for (i = 0, n = xml->xml_attrs.length; i < n; i++) {
+ attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML);
+ if (!attr)
+ continue;
+ attrns = GetNamespace(cx, attr->name, &xml->xml_namespaces);
+ JS_ASSERT(attrns);
+ if (attrns == ns)
+ return JS_TRUE;
+ }
+
+ i = XMLARRAY_FIND_MEMBER(&xml->xml_namespaces, ns, namespace_full_match);
+ if (i != XML_NOT_FOUND)
+ XMLArrayDelete(cx, &xml->xml_namespaces, i, JS_TRUE);
+
+ for (i = 0, n = xml->xml_kids.length; i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) {
+ if (!xml_removeNamespace_helper(cx, kid, ns))
+ return JS_FALSE;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+xml_removeNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ JSObject *nsobj;
+ JSXMLNamespace *ns;
+
+ XML_METHOD_PROLOG;
+ *rval = OBJECT_TO_JSVAL(obj);
+ if (xml->xml_class != JSXML_CLASS_ELEMENT)
+ return JS_TRUE;
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+
+ nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, argv);
+ if (!nsobj)
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(nsobj);
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj);
+
+ /* NOTE: remove ns from each ancestor if not used by that ancestor. */
+ return xml_removeNamespace_helper(cx, xml, ns);
+}
+
+static JSBool
+xml_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml, *vxml, *kid;
+ jsval name, value, id, junk;
+ uint32 index;
+ JSObject *nameobj;
+ JSXMLQName *nameqn;
+
+ XML_METHOD_PROLOG;
+ *rval = OBJECT_TO_JSVAL(obj);
+ if (xml->xml_class != JSXML_CLASS_ELEMENT)
+ return JS_TRUE;
+
+ value = argv[1];
+ vxml = VALUE_IS_XML(cx, value)
+ ? (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(value))
+ : NULL;
+ if (!vxml) {
+ if (!JS_ConvertValue(cx, value, JSTYPE_STRING, &argv[1]))
+ return JS_FALSE;
+ value = argv[1];
+ } else {
+ vxml = DeepCopy(cx, vxml, NULL, 0);
+ if (!vxml)
+ return JS_FALSE;
+ value = argv[1] = OBJECT_TO_JSVAL(vxml->object);
+ }
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+
+ name = argv[0];
+ if (js_IdIsIndex(name, &index))
+ return Replace(cx, xml, name, value);
+
+ /* Call function QName per spec, not ToXMLName, to avoid attribute names. */
+ nameobj = CallConstructorFunction(cx, obj, &js_QNameClass.base, 1, &name);
+ if (!nameobj)
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(nameobj);
+ nameqn = (JSXMLQName *) JS_GetPrivate(cx, nameobj);
+
+ id = JSVAL_VOID;
+ index = xml->xml_kids.length;
+ while (index != 0) {
+ --index;
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML);
+ if (kid && MatchElemName(nameqn, kid)) {
+ if (!JSVAL_IS_VOID(id) && !DeleteByIndex(cx, xml, id, &junk))
+ return JS_FALSE;
+ if (!IndexToIdVal(cx, index, &id))
+ return JS_FALSE;
+ }
+ }
+ if (JSVAL_IS_VOID(id))
+ return JS_TRUE;
+ return Replace(cx, xml, id, value);
+}
+
+static JSBool
+xml_setChildren(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ if (!PutProperty(cx, obj, ATOM_KEY(cx->runtime->atomState.starAtom),
+ &argv[0])) {
+ return JS_FALSE;
+ }
+
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+static JSBool
+xml_setLocalName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ jsval name;
+ JSXMLQName *nameqn;
+ JSString *namestr;
+
+ XML_METHOD_PROLOG;
+ if (!JSXML_HAS_NAME(xml))
+ return JS_TRUE;
+
+ name = argv[0];
+ if (!JSVAL_IS_PRIMITIVE(name) &&
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base) {
+ nameqn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(name));
+ namestr = nameqn->localName;
+ } else {
+ if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &argv[0]))
+ return JS_FALSE;
+ name = argv[0];
+ namestr = JSVAL_TO_STRING(name);
+ }
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+ xml->name->localName = namestr;
+ return JS_TRUE;
+}
+
+static JSBool
+xml_setName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml, *nsowner;
+ jsval name;
+ JSXMLQName *nameqn;
+ JSObject *nameobj;
+ JSXMLArray *nsarray;
+ uint32 i, n;
+ JSXMLNamespace *ns;
+
+ XML_METHOD_PROLOG;
+ if (!JSXML_HAS_NAME(xml))
+ return JS_TRUE;
+
+ name = argv[0];
+ if (!JSVAL_IS_PRIMITIVE(name) &&
+ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base &&
+ !(nameqn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(name)))
+ ->uri) {
+ name = argv[0] = STRING_TO_JSVAL(nameqn->localName);
+ }
+
+ nameobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &name);
+ if (!nameobj)
+ return JS_FALSE;
+ nameqn = (JSXMLQName *) JS_GetPrivate(cx, nameobj);
+
+ /* ECMA-357 13.4.4.35 Step 4. */
+ if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION)
+ nameqn->uri = cx->runtime->emptyString;
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml)
+ return JS_FALSE;
+ xml->name = nameqn;
+
+ /*
+ * Erratum: nothing in 13.4.4.35 talks about making the name match the
+ * in-scope namespaces, either by finding an in-scope namespace with a
+ * matching uri and setting the new name's prefix to that namespace's
+ * prefix, or by extending the in-scope namespaces for xml (which are in
+ * xml->parent if xml is an attribute or a PI).
+ */
+ if (xml->xml_class == JSXML_CLASS_ELEMENT) {
+ nsowner = xml;
+ } else {
+ if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT)
+ return JS_TRUE;
+ nsowner = xml->parent;
+ }
+
+ if (nameqn->prefix) {
+ /*
+ * The name being set has a prefix, which originally came from some
+ * namespace object (which may be the null namespace, where both the
+ * prefix and uri are the empty string). We must go through a full
+ * GetNamespace in case that namespace is in-scope in nsowner.
+ *
+ * If we find such an in-scope namespace, we return true right away,
+ * in this block. Otherwise, we fall through to the final return of
+ * AddInScopeNamespace(cx, nsowner, ns).
+ */
+ ns = GetNamespace(cx, nameqn, &nsowner->xml_namespaces);
+ if (!ns)
+ return JS_FALSE;
+
+ /* XXXbe have to test membership to see whether GetNamespace added */
+ if (XMLARRAY_HAS_MEMBER(&nsowner->xml_namespaces, ns, NULL))
+ return JS_TRUE;
+ } else {
+ /*
+ * At this point, we know nameqn->prefix is null, so nameqn->uri can't
+ * be the empty string (the null namespace always uses the empty string
+ * for both prefix and uri).
+ *
+ * This means we must inline GetNamespace and specialize it to match
+ * uri only, never prefix. If we find a namespace with nameqn's uri
+ * already in nsowner->xml_namespaces, then all that we need do is set
+ * nameqn->prefix to that namespace's prefix.
+ *
+ * If no such namespace exists, we can create one without going through
+ * the constructor, because we know nameqn->uri is non-empty (so prefix
+ * does not need to be converted from null to empty by QName).
+ */
+ JS_ASSERT(!IS_EMPTY(nameqn->uri));
+
+ nsarray = &nsowner->xml_namespaces;
+ for (i = 0, n = nsarray->length; i < n; i++) {
+ ns = XMLARRAY_MEMBER(nsarray, i, JSXMLNamespace);
+ if (ns && !js_CompareStrings(ns->uri, nameqn->uri)) {
+ nameqn->prefix = ns->prefix;
+ return JS_TRUE;
+ }
+ }
+
+ ns = js_NewXMLNamespace(cx, NULL, nameqn->uri, JS_TRUE);
+ if (!ns)
+ return JS_FALSE;
+ }
+
+ return AddInScopeNamespace(cx, nsowner, ns);
+}
+
+static JSBool
+xml_setNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml, *nsowner;
+ JSObject *nsobj, *qnobj;
+ JSXMLNamespace *ns;
+ jsval qnargv[2];
+
+ XML_METHOD_PROLOG;
+ if (xml->xml_class != JSXML_CLASS_ELEMENT &&
+ xml->xml_class != JSXML_CLASS_ATTRIBUTE) {
+ return JS_TRUE;
+ }
+
+ xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
+ if (!xml || !js_GetXMLQNameObject(cx, xml->name))
+ return JS_FALSE;
+
+ nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 1, argv);
+ if (!nsobj)
+ return JS_FALSE;
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj);
+ ns->declared = JS_TRUE;
+
+ qnargv[0] = argv[0] = OBJECT_TO_JSVAL(nsobj);
+ qnargv[1] = OBJECT_TO_JSVAL(xml->name->object);
+ qnobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, qnargv);
+ if (!qnobj)
+ return JS_FALSE;
+
+ xml->name = (JSXMLQName *) JS_GetPrivate(cx, qnobj);
+
+ /*
+ * Erratum: the spec fails to update the governing in-scope namespaces.
+ * See the erratum noted in xml_setName, above.
+ */
+ if (xml->xml_class == JSXML_CLASS_ELEMENT) {
+ nsowner = xml;
+ } else {
+ if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT)
+ return JS_TRUE;
+ nsowner = xml->parent;
+ }
+ return AddInScopeNamespace(cx, nsowner, ns);
+}
+
+/* XML and XMLList */
+static JSBool
+xml_text(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSXML *xml, *list, *kid, *vxml;
+ JSObject *listobj, *kidobj;
+ uint32 i, n;
+ JSBool ok;
+ jsval v;
+
+ XML_METHOD_PROLOG;
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ return JS_FALSE;
+
+ *rval = OBJECT_TO_JSVAL(listobj);
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ list->xml_target = xml;
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ ok = JS_TRUE;
+ for (i = 0, n = xml->xml_kids.length; i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) {
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ break;
+ kidobj = js_GetXMLObject(cx, kid);
+ ok = kidobj
+ ? xml_text(cx, kidobj, argc, argv, &v)
+ : JS_FALSE;
+ JS_LeaveLocalRootScope(cx);
+ if (!ok)
+ return JS_FALSE;
+ vxml = (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
+ if (JSXML_LENGTH(vxml) != 0 && !Append(cx, list, vxml))
+ return JS_FALSE;
+ }
+ }
+ } else {
+ for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
+ kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
+ if (kid && kid->xml_class == JSXML_CLASS_TEXT) {
+ if (!Append(cx, list, kid))
+ return JS_FALSE;
+ }
+ }
+ }
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_toXMLString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSString *str;
+
+ str = ToXMLString(cx, OBJECT_TO_JSVAL(obj));
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSString *
+xml_toString_helper(JSContext *cx, JSXML *xml)
+{
+ JSString *str, *kidstr;
+ JSXML *kid;
+ JSXMLArrayCursor cursor;
+
+ if (xml->xml_class == JSXML_CLASS_ATTRIBUTE ||
+ xml->xml_class == JSXML_CLASS_TEXT) {
+ return xml->xml_value;
+ }
+
+ if (!HasSimpleContent(xml))
+ return ToXMLString(cx, OBJECT_TO_JSVAL(xml->object));
+
+ str = cx->runtime->emptyString;
+ JS_EnterLocalRootScope(cx);
+ XMLArrayCursorInit(&cursor, &xml->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ if (kid->xml_class != JSXML_CLASS_COMMENT &&
+ kid->xml_class != JSXML_CLASS_PROCESSING_INSTRUCTION) {
+ kidstr = xml_toString_helper(cx, kid);
+ if (!kidstr) {
+ str = NULL;
+ break;
+ }
+ str = js_ConcatStrings(cx, str, kidstr);
+ if (!str)
+ break;
+ }
+ }
+ XMLArrayCursorFinish(&cursor);
+ JS_LeaveLocalRootScope(cx);
+ return str;
+}
+
+static JSBool
+xml_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSXML *xml;
+ JSString *str;
+
+ XML_METHOD_PROLOG;
+ str = xml_toString_helper(cx, xml);
+ if (!str)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+/* XML and XMLList */
+static JSBool
+xml_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+static JSFunctionSpec xml_methods[] = {
+ {"addNamespace", xml_addNamespace, 1,0,XML_MASK},
+ {"appendChild", xml_appendChild, 1,0,XML_MASK},
+ {js_attribute_str, xml_attribute, 1,0,GENERIC_MASK},
+ {"attributes", xml_attributes, 0,0,GENERIC_MASK},
+ {"child", xml_child, 1,0,GENERIC_MASK},
+ {"childIndex", xml_childIndex, 0,0,XML_MASK},
+ {"children", xml_children, 0,0,GENERIC_MASK},
+ {"comments", xml_comments, 0,0,GENERIC_MASK},
+ {"contains", xml_contains, 1,0,GENERIC_MASK},
+ {"copy", xml_copy, 0,0,GENERIC_MASK},
+ {"descendants", xml_descendants, 1,0,GENERIC_MASK},
+ {"elements", xml_elements, 1,0,GENERIC_MASK},
+ {"hasOwnProperty", xml_hasOwnProperty, 1,0,GENERIC_MASK},
+ {"hasComplexContent", xml_hasComplexContent, 1,0,GENERIC_MASK},
+ {"hasSimpleContent", xml_hasSimpleContent, 1,0,GENERIC_MASK},
+ {"inScopeNamespaces", xml_inScopeNamespaces, 0,0,XML_MASK},
+ {"insertChildAfter", xml_insertChildAfter, 2,0,XML_MASK},
+ {"insertChildBefore", xml_insertChildBefore, 2,0,XML_MASK},
+ {js_length_str, xml_length, 0,0,GENERIC_MASK},
+ {js_localName_str, xml_localName, 0,0,XML_MASK},
+ {js_name_str, xml_name, 0,0,XML_MASK},
+ {js_namespace_str, xml_namespace, 1,0,XML_MASK},
+ {"namespaceDeclarations", xml_namespaceDeclarations, 0,0,XML_MASK},
+ {"nodeKind", xml_nodeKind, 0,0,XML_MASK},
+ {"normalize", xml_normalize, 0,0,GENERIC_MASK},
+ {js_xml_parent_str, xml_parent, 0,0,GENERIC_MASK},
+ {"processingInstructions",xml_processingInstructions,1,0,GENERIC_MASK},
+ {"prependChild", xml_prependChild, 1,0,XML_MASK},
+ {"propertyIsEnumerable", xml_propertyIsEnumerable, 1,0,GENERIC_MASK},
+ {"removeNamespace", xml_removeNamespace, 1,0,XML_MASK},
+ {"replace", xml_replace, 2,0,XML_MASK},
+ {"setChildren", xml_setChildren, 1,0,XML_MASK},
+ {"setLocalName", xml_setLocalName, 1,0,XML_MASK},
+ {"setName", xml_setName, 1,0,XML_MASK},
+ {"setNamespace", xml_setNamespace, 1,0,XML_MASK},
+ {js_text_str, xml_text, 0,0,GENERIC_MASK},
+ {js_toString_str, xml_toString, 0,0,GENERIC_MASK},
+ {js_toXMLString_str, xml_toXMLString, 0,0,GENERIC_MASK},
+ {js_toSource_str, xml_toXMLString, 0,0,GENERIC_MASK},
+ {js_valueOf_str, xml_valueOf, 0,0,GENERIC_MASK},
+ {0,0,0,0,0}
+};
+
+static JSBool
+CopyXMLSettings(JSContext *cx, JSObject *from, JSObject *to)
+{
+ int i;
+ const char *name;
+ jsval v;
+
+ for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) {
+ name = xml_static_props[i].name;
+ if (!JS_GetProperty(cx, from, name, &v))
+ return JS_FALSE;
+ if (JSVAL_IS_BOOLEAN(v) && !JS_SetProperty(cx, to, name, &v))
+ return JS_FALSE;
+ }
+
+ name = xml_static_props[i].name;
+ if (!JS_GetProperty(cx, from, name, &v))
+ return JS_FALSE;
+ if (JSVAL_IS_NUMBER(v) && !JS_SetProperty(cx, to, name, &v))
+ return JS_FALSE;
+ return JS_TRUE;
+}
+
+static JSBool
+SetDefaultXMLSettings(JSContext *cx, JSObject *obj)
+{
+ int i;
+ jsval v;
+
+ for (i = XML_IGNORE_COMMENTS; i < XML_PRETTY_INDENT; i++) {
+ v = JSVAL_TRUE;
+ if (!JS_SetProperty(cx, obj, xml_static_props[i].name, &v))
+ return JS_FALSE;
+ }
+ v = INT_TO_JSVAL(2);
+ return JS_SetProperty(cx, obj, xml_static_props[i].name, &v);
+}
+
+static JSBool
+xml_settings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSObject *settings;
+
+ settings = JS_NewObject(cx, NULL, NULL, NULL);
+ if (!settings)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(settings);
+ return CopyXMLSettings(cx, obj, settings);
+}
+
+static JSBool
+xml_setSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ jsval v;
+ JSBool ok;
+ JSObject *settings;
+
+ v = argv[0];
+ if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) {
+ cx->xmlSettingFlags = 0;
+ ok = SetDefaultXMLSettings(cx, obj);
+ } else {
+ if (JSVAL_IS_PRIMITIVE(v))
+ return JS_TRUE;
+ settings = JSVAL_TO_OBJECT(v);
+ cx->xmlSettingFlags = 0;
+ ok = CopyXMLSettings(cx, settings, obj);
+ }
+ if (ok)
+ cx->xmlSettingFlags |= XSF_CACHE_VALID;
+ return ok;
+}
+
+static JSBool
+xml_defaultSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ JSObject *settings;
+
+ settings = JS_NewObject(cx, NULL, NULL, NULL);
+ if (!settings)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(settings);
+ return SetDefaultXMLSettings(cx, settings);
+}
+
+static JSFunctionSpec xml_static_methods[] = {
+ {"settings", xml_settings, 0,0,0},
+ {"setSettings", xml_setSettings, 1,0,0},
+ {"defaultSettings", xml_defaultSettings, 0,0,0},
+ {0,0,0,0,0}
+};
+
+static JSBool
+XML(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+ JSXML *xml, *copy;
+ JSObject *xobj, *vobj;
+ JSClass *clasp;
+
+ v = argv[0];
+ if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v))
+ v = STRING_TO_JSVAL(cx->runtime->emptyString);
+
+ xobj = ToXML(cx, v);
+ if (!xobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(xobj);
+ xml = (JSXML *) JS_GetPrivate(cx, xobj);
+
+ if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) {
+ vobj = JSVAL_TO_OBJECT(v);
+ clasp = OBJ_GET_CLASS(cx, vobj);
+ if (clasp == &js_XMLClass ||
+ (clasp->flags & JSCLASS_DOCUMENT_OBSERVER)) {
+ /* No need to lock obj, it's newly constructed and thread local. */
+ copy = DeepCopy(cx, xml, obj, 0);
+ if (!copy)
+ return JS_FALSE;
+ JS_ASSERT(copy->object == obj);
+ *rval = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+XMLList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ jsval v;
+ JSObject *vobj, *listobj;
+ JSXML *xml, *list;
+
+ v = argv[0];
+ if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v))
+ v = STRING_TO_JSVAL(cx->runtime->emptyString);
+
+ if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) {
+ vobj = JSVAL_TO_OBJECT(v);
+ if (OBJECT_IS_XML(cx, vobj)) {
+ xml = (JSXML *) JS_GetPrivate(cx, vobj);
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ return JS_FALSE;
+ *rval = OBJECT_TO_JSVAL(listobj);
+
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ if (!Append(cx, list, xml))
+ return JS_FALSE;
+ return JS_TRUE;
+ }
+ }
+ }
+
+ /* Toggle on XML support since the script has explicitly requested it. */
+ listobj = ToXMLList(cx, v);
+ if (!listobj)
+ return JS_FALSE;
+
+ *rval = OBJECT_TO_JSVAL(listobj);
+ return JS_TRUE;
+}
+
+#define JSXML_LIST_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLListVar))
+#define JSXML_ELEMENT_SIZE (offsetof(JSXML, u) + sizeof(struct JSXMLVar))
+#define JSXML_LEAF_SIZE (offsetof(JSXML, u) + sizeof(JSString *))
+
+static size_t sizeof_JSXML[JSXML_CLASS_LIMIT] = {
+ JSXML_LIST_SIZE, /* JSXML_CLASS_LIST */
+ JSXML_ELEMENT_SIZE, /* JSXML_CLASS_ELEMENT */
+ JSXML_LEAF_SIZE, /* JSXML_CLASS_ATTRIBUTE */
+ JSXML_LEAF_SIZE, /* JSXML_CLASS_PROCESSING_INSTRUCTION */
+ JSXML_LEAF_SIZE, /* JSXML_CLASS_TEXT */
+ JSXML_LEAF_SIZE /* JSXML_CLASS_COMMENT */
+};
+
+#ifdef DEBUG_notme
+JSCList xml_leaks = JS_INIT_STATIC_CLIST(&xml_leaks);
+uint32 xml_serial;
+#endif
+
+JSXML *
+js_NewXML(JSContext *cx, JSXMLClass xml_class)
+{
+ JSXML *xml;
+
+ xml = (JSXML *) js_NewGCThing(cx, GCX_XML, sizeof_JSXML[xml_class]);
+ if (!xml)
+ return NULL;
+
+ xml->object = NULL;
+ xml->domnode = NULL;
+ xml->parent = NULL;
+ xml->name = NULL;
+ xml->xml_class = xml_class;
+ xml->xml_flags = 0;
+ if (JSXML_CLASS_HAS_VALUE(xml_class)) {
+ xml->xml_value = cx->runtime->emptyString;
+ } else {
+ XMLArrayInit(cx, &xml->xml_kids, 0);
+ if (xml_class == JSXML_CLASS_LIST) {
+ xml->xml_target = NULL;
+ xml->xml_targetprop = NULL;
+ } else {
+ XMLArrayInit(cx, &xml->xml_namespaces, 0);
+ XMLArrayInit(cx, &xml->xml_attrs, 0);
+ }
+ }
+
+#ifdef DEBUG_notme
+ JS_APPEND_LINK(&xml->links, &xml_leaks);
+ xml->serial = xml_serial++;
+#endif
+ METER(xml_stats.xml);
+ METER(xml_stats.livexml);
+ return xml;
+}
+
+static void
+xml_mark_tail(JSContext *cx, JSXML *xml, void *arg)
+{
+ XMLArrayTrim(&xml->xml_kids);
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ if (xml->xml_target)
+ JS_MarkGCThing(cx, xml->xml_target, "target", arg);
+ if (xml->xml_targetprop)
+ JS_MarkGCThing(cx, xml->xml_targetprop, "targetprop", arg);
+ } else {
+ namespace_mark_vector(cx,
+ (JSXMLNamespace **) xml->xml_namespaces.vector,
+ xml->xml_namespaces.length,
+ arg);
+ XMLArrayCursorMark(cx, xml->xml_namespaces.cursors);
+ XMLArrayTrim(&xml->xml_namespaces);
+
+ xml_mark_vector(cx,
+ (JSXML **) xml->xml_attrs.vector,
+ xml->xml_attrs.length,
+ arg);
+ XMLArrayCursorMark(cx, xml->xml_attrs.cursors);
+ XMLArrayTrim(&xml->xml_attrs);
+ }
+}
+
+void
+js_MarkXML(JSContext *cx, JSXML *xml, void *arg)
+{
+ JS_MarkGCThing(cx, xml->object, js_object_str, arg);
+ JS_MarkGCThing(cx, xml->name, js_name_str, arg);
+ JS_MarkGCThing(cx, xml->parent, js_xml_parent_str, arg);
+
+ if (JSXML_HAS_VALUE(xml)) {
+ JS_MarkGCThing(cx, xml->xml_value, "value", arg);
+ } else {
+ xml_mark_vector(cx,
+ (JSXML **) xml->xml_kids.vector,
+ xml->xml_kids.length,
+ arg);
+ XMLArrayCursorMark(cx, xml->xml_kids.cursors);
+
+ xml_mark_tail(cx, xml, arg);
+ }
+}
+
+void
+js_FinalizeXML(JSContext *cx, JSXML *xml)
+{
+ if (JSXML_HAS_KIDS(xml)) {
+ XMLArrayFinish(cx, &xml->xml_kids);
+ if (xml->xml_class == JSXML_CLASS_ELEMENT) {
+ XMLArrayFinish(cx, &xml->xml_namespaces);
+ XMLArrayFinish(cx, &xml->xml_attrs);
+ }
+ }
+
+#ifdef DEBUG_notme
+ JS_REMOVE_LINK(&xml->links);
+#endif
+
+ UNMETER(xml_stats.livexml);
+}
+
+JSObject *
+js_ParseNodeToXMLObject(JSContext *cx, JSParseNode *pn)
+{
+ jsval nsval;
+ JSXMLNamespace *ns;
+ JSXMLArray nsarray;
+ JSXML *xml;
+
+ if (!js_GetDefaultXMLNamespace(cx, &nsval))
+ return NULL;
+ JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval));
+ ns = (JSXMLNamespace *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(nsval));
+
+ if (!XMLArrayInit(cx, &nsarray, 1))
+ return NULL;
+
+ XMLARRAY_APPEND(cx, &nsarray, ns);
+ xml = ParseNodeToXML(cx, pn, &nsarray, XSF_PRECOMPILED_ROOT);
+ XMLArrayFinish(cx, &nsarray);
+ if (!xml)
+ return NULL;
+
+ return xml->object;
+}
+
+JSObject *
+js_NewXMLObject(JSContext *cx, JSXMLClass xml_class)
+{
+ JSXML *xml;
+ JSObject *obj;
+ JSTempValueRooter tvr;
+
+ xml = js_NewXML(cx, xml_class);
+ if (!xml)
+ return NULL;
+ JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(xml), &tvr);
+ obj = js_GetXMLObject(cx, xml);
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return obj;
+}
+
+static JSObject *
+NewXMLObject(JSContext *cx, JSXML *xml)
+{
+ JSObject *obj;
+
+ obj = js_NewObject(cx, &js_XMLClass, NULL, NULL);
+ if (!obj || !JS_SetPrivate(cx, obj, xml)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ METER(xml_stats.xmlobj);
+ METER(xml_stats.livexmlobj);
+ return obj;
+}
+
+JSObject *
+js_GetXMLObject(JSContext *cx, JSXML *xml)
+{
+ JSObject *obj;
+
+ obj = xml->object;
+ if (obj) {
+ JS_ASSERT(JS_GetPrivate(cx, obj) == xml);
+ return obj;
+ }
+
+ /*
+ * A JSXML cannot be shared among threads unless it has an object.
+ * A JSXML cannot be given an object unless:
+ * (a) it has no parent; or
+ * (b) its parent has no object (therefore is thread-private); or
+ * (c) its parent's object is locked.
+ *
+ * Once given an object, a JSXML is immutable.
+ */
+ JS_ASSERT(!xml->parent ||
+ !xml->parent->object ||
+ JS_IS_OBJ_LOCKED(cx, xml->parent->object));
+
+ obj = NewXMLObject(cx, xml);
+ if (!obj)
+ return NULL;
+ xml->object = obj;
+ return obj;
+}
+
+JSObject *
+js_InitNamespaceClass(JSContext *cx, JSObject *obj)
+{
+ return JS_InitClass(cx, obj, NULL, &js_NamespaceClass.base, Namespace, 2,
+ namespace_props, namespace_methods, NULL, NULL);
+}
+
+JSObject *
+js_InitQNameClass(JSContext *cx, JSObject *obj)
+{
+ return JS_InitClass(cx, obj, NULL, &js_QNameClass.base, QName, 2,
+ qname_props, qname_methods, NULL, NULL);
+}
+
+JSObject *
+js_InitAttributeNameClass(JSContext *cx, JSObject *obj)
+{
+ return JS_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2,
+ qname_props, qname_methods, NULL, NULL);
+}
+
+JSObject *
+js_InitAnyNameClass(JSContext *cx, JSObject *obj)
+{
+ jsval v;
+
+ if (!js_GetAnyName(cx, &v))
+ return NULL;
+ return JSVAL_TO_OBJECT(v);
+}
+
+JSObject *
+js_InitXMLClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto, *pobj, *ctor;
+ JSFunctionSpec *fs;
+ JSFunction *fun;
+ JSXML *xml;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+ jsval cval, argv[1], junk;
+
+ /* Define the isXMLName function. */
+ if (!JS_DefineFunction(cx, obj, js_isXMLName_str, xml_isXMLName, 1, 0))
+ return NULL;
+
+ /* Define the XML class constructor and prototype. */
+ proto = JS_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1,
+ NULL, NULL,
+ xml_static_props, xml_static_methods);
+ if (!proto)
+ return NULL;
+
+ /*
+ * XXX Hack alert: expand JS_DefineFunctions here to copy fs->extra into
+ * fun->spare, clearing fun->extra. No xml_methods require extra local GC
+ * roots allocated after actual arguments on the VM stack, but we need a
+ * way to tell which methods work only on XML objects, which work only on
+ * XMLList objects, and which work on either.
+ */
+ for (fs = xml_methods; fs->name; fs++) {
+ fun = JS_DefineFunction(cx, proto, fs->name, fs->call, fs->nargs,
+ fs->flags);
+ if (!fun)
+ return NULL;
+ fun->extra = 0;
+ fun->spare = fs->extra;
+ }
+
+ xml = js_NewXML(cx, JSXML_CLASS_TEXT);
+ if (!xml || !JS_SetPrivate(cx, proto, xml))
+ return NULL;
+ xml->object = proto;
+ METER(xml_stats.xmlobj);
+ METER(xml_stats.livexmlobj);
+
+ /*
+ * Prepare to set default settings on the XML constructor we just made.
+ * NB: We can't use JS_GetConstructor, because it calls OBJ_GET_PROPERTY,
+ * which is xml_getProperty, which creates a new XMLList every time! We
+ * must instead call js_LookupProperty directly.
+ */
+ if (!js_LookupProperty(cx, proto,
+ ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
+ &pobj, &prop)) {
+ return NULL;
+ }
+ JS_ASSERT(prop);
+ sprop = (JSScopeProperty *) prop;
+ JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)));
+ cval = OBJ_GET_SLOT(cx, pobj, sprop->slot);
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+ JS_ASSERT(JSVAL_IS_FUNCTION(cx, cval));
+
+ /* Set default settings. */
+ ctor = JSVAL_TO_OBJECT(cval);
+ argv[0] = JSVAL_VOID;
+ if (!xml_setSettings(cx, ctor, 1, argv, &junk))
+ return NULL;
+
+ /* Define the XMLList function and give it the same prototype as XML. */
+ fun = JS_DefineFunction(cx, obj, js_XMLList_str, XMLList, 1, 0);
+ if (!fun)
+ return NULL;
+ if (!js_SetClassPrototype(cx, fun->object, proto,
+ JSPROP_READONLY | JSPROP_PERMANENT)) {
+ return NULL;
+ }
+ return proto;
+}
+
+JSObject *
+js_InitXMLClasses(JSContext *cx, JSObject *obj)
+{
+ if (!js_InitNamespaceClass(cx, obj))
+ return NULL;
+ if (!js_InitQNameClass(cx, obj))
+ return NULL;
+ if (!js_InitAttributeNameClass(cx, obj))
+ return NULL;
+ if (!js_InitAnyNameClass(cx, obj))
+ return NULL;
+ return js_InitXMLClass(cx, obj);
+}
+
+JSBool
+js_GetFunctionNamespace(JSContext *cx, jsval *vp)
+{
+ JSRuntime *rt;
+ JSObject *obj;
+ JSAtom *atom;
+ JSString *prefix, *uri;
+
+ /* An invalid URI, for internal use only, guaranteed not to collide. */
+ static const char anti_uri[] = "@mozilla.org/js/function";
+
+ rt = cx->runtime;
+ obj = rt->functionNamespaceObject;
+ if (!obj) {
+ atom = js_Atomize(cx, js_function_str, 8, 0);
+ JS_ASSERT(atom);
+ prefix = ATOM_TO_STRING(atom);
+
+ atom = js_Atomize(cx, anti_uri, sizeof anti_uri - 1, ATOM_PINNED);
+ if (!atom)
+ return JS_FALSE;
+ rt->atomState.lazy.functionNamespaceURIAtom = atom;
+
+ uri = ATOM_TO_STRING(atom);
+ obj = js_NewXMLNamespaceObject(cx, prefix, uri, JS_FALSE);
+ if (!obj)
+ return JS_FALSE;
+
+ /*
+ * Avoid entraining any in-scope Object.prototype. The loss of
+ * Namespace.prototype is not detectable, as there is no way to
+ * refer to this instance in scripts. When used to qualify method
+ * names, its prefix and uri references are copied to the QName.
+ */
+ OBJ_SET_PROTO(cx, obj, NULL);
+ OBJ_SET_PARENT(cx, obj, NULL);
+ rt->functionNamespaceObject = obj;
+ }
+ *vp = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+/*
+ * Note the asymmetry between js_GetDefaultXMLNamespace and js_SetDefaultXML-
+ * Namespace. Get searches fp->scopeChain for JS_DEFAULT_XML_NAMESPACE_ID,
+ * while Set sets JS_DEFAULT_XML_NAMESPACE_ID in fp->varobj (unless fp is a
+ * lightweight function activation). There's no requirement that fp->varobj
+ * lie directly on fp->scopeChain, although it should be reachable using the
+ * prototype chain from a scope object (cf. JSOPTION_VAROBJFIX in jsapi.h).
+ *
+ * If Get can't find JS_DEFAULT_XML_NAMESPACE_ID along the scope chain, it
+ * creates a default namespace via 'new Namespace()'. In contrast, Set uses
+ * its v argument as the uri of a new Namespace, with "" as the prefix. See
+ * ECMA-357 12.1 and 12.1.1. Note that if Set is called with a Namespace n,
+ * the default XML namespace will be set to ("", n.uri). So the uri string
+ * is really the only usefully stored value of the default namespace.
+ */
+JSBool
+js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
+{
+ JSStackFrame *fp;
+ JSObject *nsobj, *obj, *tmp;
+ jsval v;
+
+ fp = cx->fp;
+ nsobj = fp->xmlNamespace;
+ if (nsobj) {
+ *vp = OBJECT_TO_JSVAL(nsobj);
+ return JS_TRUE;
+ }
+
+ obj = NULL;
+ for (tmp = fp->scopeChain; tmp; tmp = OBJ_GET_PARENT(cx, obj)) {
+ obj = tmp;
+ if (!OBJ_GET_PROPERTY(cx, obj, JS_DEFAULT_XML_NAMESPACE_ID, &v))
+ return JS_FALSE;
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ fp->xmlNamespace = JSVAL_TO_OBJECT(v);
+ *vp = v;
+ return JS_TRUE;
+ }
+ }
+
+ nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 0, NULL);
+ if (!nsobj)
+ return JS_FALSE;
+ v = OBJECT_TO_JSVAL(nsobj);
+ if (obj &&
+ !OBJ_DEFINE_PROPERTY(cx, obj, JS_DEFAULT_XML_NAMESPACE_ID, v,
+ JS_PropertyStub, JS_PropertyStub,
+ JSPROP_PERMANENT, NULL)) {
+ return JS_FALSE;
+ }
+ fp->xmlNamespace = nsobj;
+ *vp = v;
+ return JS_TRUE;
+}
+
+JSBool
+js_SetDefaultXMLNamespace(JSContext *cx, jsval v)
+{
+ jsval argv[2];
+ JSObject *nsobj, *varobj;
+ JSStackFrame *fp;
+
+ argv[0] = STRING_TO_JSVAL(cx->runtime->emptyString);
+ argv[1] = v;
+ nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL,
+ 2, argv);
+ if (!nsobj)
+ return JS_FALSE;
+ v = OBJECT_TO_JSVAL(nsobj);
+
+ fp = cx->fp;
+ varobj = fp->varobj;
+ if (varobj) {
+ if (!OBJ_DEFINE_PROPERTY(cx, varobj, JS_DEFAULT_XML_NAMESPACE_ID, v,
+ JS_PropertyStub, JS_PropertyStub,
+ JSPROP_PERMANENT, NULL)) {
+ return JS_FALSE;
+ }
+ } else {
+ JS_ASSERT(fp->fun && !(fp->fun->flags & JSFUN_HEAVYWEIGHT));
+ }
+ fp->xmlNamespace = JSVAL_TO_OBJECT(v);
+ return JS_TRUE;
+}
+
+JSBool
+js_ToAttributeName(JSContext *cx, jsval *vp)
+{
+ JSXMLQName *qn;
+
+ qn = ToAttributeName(cx, *vp);
+ if (!qn)
+ return JS_FALSE;
+ *vp = OBJECT_TO_JSVAL(qn->object);
+ return JS_TRUE;
+}
+
+JSString *
+js_EscapeAttributeValue(JSContext *cx, JSString *str)
+{
+ return EscapeAttributeValue(cx, NULL, str);
+}
+
+JSString *
+js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2)
+{
+ size_t len, len2, newlen;
+ jschar *chars;
+
+ if (JSSTRING_IS_DEPENDENT(str) ||
+ !(*js_GetGCThingFlags(str) & GCF_MUTABLE)) {
+ str = js_NewStringCopyN(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
+ 0);
+ if (!str)
+ return NULL;
+ }
+
+ len = str->length;
+ len2 = JSSTRING_LENGTH(str2);
+ newlen = (isName) ? len + 1 + len2 : len + 2 + len2 + 1;
+ chars = (jschar *) JS_realloc(cx, str->chars, (newlen+1) * sizeof(jschar));
+ if (!chars)
+ return NULL;
+
+ /*
+ * Reallocating str (because we know it has no other references) requires
+ * purging any deflated string cached for it.
+ */
+ js_PurgeDeflatedStringCache(str);
+
+ str->chars = chars;
+ str->length = newlen;
+ chars += len;
+ if (isName) {
+ *chars++ = ' ';
+ js_strncpy(chars, JSSTRING_CHARS(str2), len2);
+ chars += len2;
+ } else {
+ *chars++ = '=';
+ *chars++ = '"';
+ js_strncpy(chars, JSSTRING_CHARS(str2), len2);
+ chars += len2;
+ *chars++ = '"';
+ }
+ *chars = 0;
+ return str;
+}
+
+JSString *
+js_EscapeElementValue(JSContext *cx, JSString *str)
+{
+ return EscapeElementValue(cx, NULL, str);
+}
+
+JSString *
+js_ValueToXMLString(JSContext *cx, jsval v)
+{
+ return ToXMLString(cx, v);
+}
+
+static JSBool
+anyname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ *rval = ATOM_KEY(cx->runtime->atomState.starAtom);
+ return JS_TRUE;
+}
+
+JSBool
+js_GetAnyName(JSContext *cx, jsval *vp)
+{
+ JSRuntime *rt;
+ JSObject *obj;
+ JSXMLQName *qn;
+
+ rt = cx->runtime;
+ obj = rt->anynameObject;
+ if (!obj) {
+ qn = js_NewXMLQName(cx, rt->emptyString, rt->emptyString,
+ ATOM_TO_STRING(rt->atomState.starAtom));
+ if (!qn)
+ return JS_FALSE;
+
+ obj = js_NewObject(cx, &js_AnyNameClass, NULL, NULL);
+ if (!obj || !JS_SetPrivate(cx, obj, qn)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return JS_FALSE;
+ }
+ qn->object = obj;
+ METER(xml_stats.qnameobj);
+ METER(xml_stats.liveqnameobj);
+
+ /*
+ * Avoid entraining any in-scope Object.prototype. This loses the
+ * default toString inheritance, but no big deal: we want a better
+ * custom one for clearer diagnostics.
+ */
+ if (!JS_DefineFunction(cx, obj, js_toString_str, anyname_toString,
+ 0, 0)) {
+ return JS_FALSE;
+ }
+ OBJ_SET_PROTO(cx, obj, NULL);
+ JS_ASSERT(!OBJ_GET_PARENT(cx, obj));
+ rt->anynameObject = obj;
+ }
+ *vp = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
+}
+
+JSBool
+js_FindXMLProperty(JSContext *cx, jsval name, JSObject **objp, jsval *namep)
+{
+ JSXMLQName *qn;
+ jsid funid, id;
+ JSObject *obj, *pobj, *lastobj;
+ JSProperty *prop;
+ const char *printable;
+
+ qn = ToXMLName(cx, name, &funid);
+ if (!qn)
+ return JS_FALSE;
+ id = OBJECT_TO_JSID(qn->object);
+
+ obj = cx->fp->scopeChain;
+ do {
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
+ return JS_FALSE;
+ if (prop) {
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
+
+ /*
+ * Call OBJ_THIS_OBJECT to skip any With object that wraps an XML
+ * object to carry scope chain linkage in js_FilterXMLList.
+ */
+ pobj = OBJ_THIS_OBJECT(cx, obj);
+ if (OBJECT_IS_XML(cx, pobj)) {
+ *objp = pobj;
+ *namep = ID_TO_VALUE(id);
+ return JS_TRUE;
+ }
+ }
+
+ lastobj = obj;
+ } while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL);
+
+ printable = js_ValueToPrintableString(cx, name);
+ if (printable) {
+ JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
+ js_GetErrorMessage, NULL,
+ JSMSG_UNDEFINED_XML_NAME, printable);
+ }
+ return JS_FALSE;
+}
+
+JSBool
+js_GetXMLProperty(JSContext *cx, JSObject *obj, jsval name, jsval *vp)
+{
+ return GetProperty(cx, obj, name, vp);
+}
+
+JSBool
+js_SetXMLProperty(JSContext *cx, JSObject *obj, jsval name, jsval *vp)
+{
+ return PutProperty(cx, obj, name, vp);
+}
+
+static JSXML *
+GetPrivate(JSContext *cx, JSObject *obj, const char *method)
+{
+ JSXML *xml;
+
+ xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
+ if (!xml) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_INCOMPATIBLE_METHOD,
+ js_XML_str, method, OBJ_GET_CLASS(cx, obj)->name);
+ }
+ return xml;
+}
+
+JSBool
+js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ JSXML *xml, *list;
+
+ xml = GetPrivate(cx, obj, "descendants internal method");
+ if (!xml)
+ return JS_FALSE;
+
+ list = Descendants(cx, xml, id);
+ if (!list)
+ return JS_FALSE;
+ *vp = OBJECT_TO_JSVAL(list->object);
+ return JS_TRUE;
+}
+
+JSBool
+js_DeleteXMLListElements(JSContext *cx, JSObject *listobj)
+{
+ JSXML *list;
+ uint32 n;
+ jsval junk;
+
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ for (n = list->xml_kids.length; n != 0; --n) {
+ if (!DeleteProperty(cx, listobj, INT_TO_JSID(0), &junk))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JSBool
+js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, jsval *vp)
+{
+ JSBool ok, match;
+ JSStackFrame *fp;
+ JSObject *scobj, *listobj, *resobj, *withobj, *kidobj;
+ JSXML *xml, *list, *result, *kid;
+ JSXMLArrayCursor cursor;
+
+ ok = JS_EnterLocalRootScope(cx);
+ if (!ok)
+ return JS_FALSE;
+
+ /* All control flow after this point must exit via label out or bad. */
+ fp = cx->fp;
+ scobj = fp->scopeChain;
+ withobj = NULL;
+ xml = GetPrivate(cx, obj, "filtering predicate operator");
+ if (!xml)
+ goto bad;
+
+ if (xml->xml_class == JSXML_CLASS_LIST) {
+ list = xml;
+ } else {
+ listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!listobj)
+ goto bad;
+ list = (JSXML *) JS_GetPrivate(cx, listobj);
+ ok = Append(cx, list, xml);
+ if (!ok)
+ goto out;
+ }
+
+ resobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
+ if (!resobj)
+ goto bad;
+ result = (JSXML *) JS_GetPrivate(cx, resobj);
+
+ /* Hoist the scope chain update out of the loop over kids. */
+ withobj = js_NewWithObject(cx, NULL, scobj, -1);
+ if (!withobj)
+ goto bad;
+ fp->scopeChain = withobj;
+
+ XMLArrayCursorInit(&cursor, &list->xml_kids);
+ while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
+ kidobj = js_GetXMLObject(cx, kid);
+ if (!kidobj)
+ break;
+ OBJ_SET_PROTO(cx, withobj, kidobj);
+ ok = js_Interpret(cx, pc, vp) && js_ValueToBoolean(cx, *vp, &match);
+ if (ok && match)
+ ok = Append(cx, result, kid);
+ if (!ok)
+ break;
+ }
+ XMLArrayCursorFinish(&cursor);
+ if (!ok)
+ goto out;
+ if (kid)
+ goto bad;
+
+ *vp = OBJECT_TO_JSVAL(resobj);
+
+out:
+ if (withobj) {
+ fp->scopeChain = scobj;
+ JS_SetPrivate(cx, withobj, NULL);
+ }
+ JS_LeaveLocalRootScope(cx);
+ return ok;
+bad:
+ ok = JS_FALSE;
+ goto out;
+}
+
+JSObject *
+js_ValueToXMLObject(JSContext *cx, jsval v)
+{
+ return ToXML(cx, v);
+}
+
+JSObject *
+js_ValueToXMLListObject(JSContext *cx, jsval v)
+{
+ return ToXMLList(cx, v);
+}
+
+JSObject *
+js_CloneXMLObject(JSContext *cx, JSObject *obj)
+{
+ uintN flags;
+ JSXML *xml;
+
+ if (!GetXMLSettingFlags(cx, &flags))
+ return NULL;
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ if (flags & (XSF_IGNORE_COMMENTS |
+ XSF_IGNORE_PROCESSING_INSTRUCTIONS |
+ XSF_IGNORE_WHITESPACE)) {
+ xml = DeepCopy(cx, xml, NULL, flags);
+ if (!xml)
+ return NULL;
+ return xml->object;
+ }
+ return NewXMLObject(cx, xml);
+}
+
+JSObject *
+js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name,
+ JSString *value)
+{
+ uintN flags;
+ JSObject *obj;
+ JSXML *xml;
+ JSXMLQName *qn;
+
+ if (!GetXMLSettingFlags(cx, &flags))
+ return NULL;
+
+ if ((xml_class == JSXML_CLASS_COMMENT &&
+ (flags & XSF_IGNORE_COMMENTS)) ||
+ (xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION &&
+ (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS))) {
+ return js_NewXMLObject(cx, JSXML_CLASS_TEXT);
+ }
+
+ obj = js_NewXMLObject(cx, xml_class);
+ if (!obj)
+ return NULL;
+ xml = (JSXML *) JS_GetPrivate(cx, obj);
+ if (name) {
+ qn = js_NewXMLQName(cx, cx->runtime->emptyString, NULL, name);
+ if (!qn)
+ return NULL;
+ xml->name = qn;
+ }
+ xml->xml_value = value;
+ return obj;
+}
+
+JSString *
+js_MakeXMLCDATAString(JSContext *cx, JSString *str)
+{
+ return MakeXMLCDATAString(cx, NULL, str);
+}
+
+JSString *
+js_MakeXMLCommentString(JSContext *cx, JSString *str)
+{
+ return MakeXMLCommentString(cx, NULL, str);
+}
+
+JSString *
+js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str)
+{
+ return MakeXMLPIString(cx, NULL, name, str);
+}
+
+#endif /* JS_HAS_XML_SUPPORT */
diff --git a/src/dom/js/jsxml.h b/src/dom/js/jsxml.h
--- /dev/null
+++ b/src/dom/js/jsxml.h
@@ -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___ */
diff --git a/src/dom/js/prmjtime.c b/src/dom/js/prmjtime.c
index 774f83999c41cdadce4551f758ccaf517d41df4f..6e08423af8009f17137540d2d915de8d855c332f 100644 (file)
--- a/src/dom/js/prmjtime.c
+++ b/src/dom/js/prmjtime.c
#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> */
#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(¤tLocalTimeSeconds);
-
- 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)) || \
return mktime(<ime) - (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 */
struct timeval tv;
JSInt64 s, us, s2us;
#endif /* XP_UNIX */
-#ifdef XP_MAC
- JSUint64 upTime;
- JSInt64 localTime;
- JSInt64 gmtOffset;
- JSInt64 dstOffset;
- JSInt32 gmtDiff;
- JSInt64 s2us;
-#endif /* XP_MAC */
#ifdef XP_OS2
ftime(&b);
JSLL_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 */
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;
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
diff --git a/src/dom/js/prmjtime.h b/src/dom/js/prmjtime.h
index 6a94a11b1673f5377a8334b4b1a4060f33f2177c..b74fe845eb67a8c19dd313c06f48d7ae56891898 100644 (file)
--- a/src/dom/js/prmjtime.h
+++ b/src/dom/js/prmjtime.h
* 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